﻿predis/docker/unstable_cluster/create_cluster.sh                                                    0000644                 00000002200 15233650113 0016210 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       #! /bin/bash

mkdir -p /nodes
touch /nodes/nodemap
if [ -z ${START_PORT} ]; then
    START_PORT=6372
fi
if [ -z ${END_PORT} ]; then
    END_PORT=6377
fi
if [ ! -z "$3" ]; then
    START_PORT=$2
    START_PORT=$3
fi
echo "STARTING: ${START_PORT}"
echo "ENDING: ${END_PORT}"

for PORT in `seq ${START_PORT} ${END_PORT}`; do
  mkdir -p /nodes/$PORT
  if [[ -e /redis.conf ]]; then
    cp /redis.conf /nodes/$PORT/redis.conf
  else
    touch /nodes/$PORT/redis.conf
  fi
  cat << EOF >> /nodes/$PORT/redis.conf
port ${PORT}
cluster-enabled yes
daemonize yes
logfile /redis.log
dir /nodes/$PORT
EOF

  set -x
  /opt/redis-stack/bin/redis-server /nodes/$PORT/redis.conf
  sleep 1
  if [ $? -ne 0 ]; then
    echo "Redis failed to start, exiting."
    continue
  fi
  echo 127.0.0.1:$PORT >> /nodes/nodemap
done
if [ -z "${REDIS_PASSWORD}" ]; then
    echo yes | /opt/redis-stack/bin/redis-cli --cluster create `seq -f 127.0.0.1:%g ${START_PORT} ${END_PORT}` --cluster-replicas 1
else
    echo yes | opt/redis-stack/bin/redis-cli -a ${REDIS_PASSWORD} --cluster create `seq -f 127.0.0.1:%g ${START_PORT} ${END_PORT}` --cluster-replicas 1
fi
tail -f /redis.log
                                                                                                                                                                                                                                                                                                                                                                                                predis/docker/unstable_cluster/redis.conf                                                           0000644                 00000000574 15233650113 0014641 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       # Redis Cluster config file will be shared across all nodes.
# Do not change the following configurations that are already set:
# port, cluster-enabled, daemonize, logfile, dir
protected-mode no
loadmodule /opt/redis-stack/lib/redisearch.so
loadmodule /opt/redis-stack/lib/redistimeseries.so
loadmodule /opt/redis-stack/lib/rejson.so
loadmodule /opt/redis-stack/lib/redisbloom.so
                                                                                                                                    predis/docker/unstable_cluster/docker-compose.yml                                                   0000644                 00000000466 15233650113 0016321 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       version: "3.9"
services:
  cluster:
    container_name: redis-cluster
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "6372:6372"
      - "6373:6373"
      - "6374:6374"
      - "6375:6375"
      - "6376:6376"
      - "6377:6378"
    volumes:
      - "./redis.conf:/redis.conf:ro"

                                                                                                                                                                                                          predis/docker/unstable_cluster/Dockerfile                                                           0000644                 00000000267 15233650113 0014655 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       FROM redis/redis-stack-server:latest as rss

COPY create_cluster.sh /create_cluster.sh
RUN ls -R /opt/redis-stack
RUN chmod a+x /create_cluster.sh

ENTRYPOINT [ "/create_cluster.sh"]
                                                                                                                                                                                                                                                                                                                                         predis/composer.json                                                                                0000644                 00000002444 15233650113 0010557 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       {
    "name": "predis/predis",
    "type": "library",
    "description": "A flexible and feature-complete Redis client for PHP.",
    "keywords": ["nosql", "redis", "predis"],
    "homepage": "http://github.com/predis/predis",
    "license": "MIT",
    "support": {
        "issues": "https://github.com/predis/predis/issues"
    },
    "authors": [
        {
            "name": "Till Krüss",
            "homepage": "https://till.im",
            "role": "Maintainer"
        }
    ],
    "funding": [
        {
            "type": "github",
            "url": "https://github.com/sponsors/tillkruss"
        }
    ],
    "require": {
        "php": "^7.2 || ^8.0"
    },
    "require-dev": {
        "friendsofphp/php-cs-fixer": "^3.3",
        "phpstan/phpstan": "^1.9",
        "phpunit/phpunit": "^8.0 || ~9.4.4"
    },
    "suggest": {
        "ext-relay": "Faster connection with in-memory caching (>=0.6.2)"
    },
    "scripts": {
        "phpstan": "phpstan analyse",
        "style": "php-cs-fixer fix --diff --dry-run",
        "style:fix": "php-cs-fixer fix"
    },
    "autoload": {
        "psr-4": {
            "Predis\\": "src/"
        }
    },
    "config": {
        "sort-packages": true,
        "preferred-install": "dist"
    },
    "minimum-stability": "dev",
    "prefer-stable": true
}
                                                                                                                                                                                                                            predis/README.md                                                                                    0000644                 00000047724 15233650113 0007326 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       # Predis #

[![Software license][ico-license]](LICENSE)
[![Latest stable][ico-version-stable]][link-releases]
[![Latest development][ico-version-dev]][link-releases]
[![Monthly installs][ico-downloads-monthly]][link-downloads]
[![Build status][ico-build]][link-actions]
[![Coverage Status][ico-coverage]][link-coverage]

A flexible and feature-complete [Redis](http://redis.io) client for PHP 7.2 and newer.

More details about this project can be found on the [frequently asked questions](FAQ.md).


## Main features ##

- Support for Redis from __3.0__ to __7.0__.
- 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).
- Transparent key prefixing of keys using a customizable prefix strategy.
- Command pipelining on both single nodes and clusters (client-side sharding only).
- Abstraction for Redis transactions (Redis >= 2.0) and CAS operations (Redis >= 2.2).
- Abstraction for Lua scripting (Redis >= 2.6) and automatic switching between `EVALSHA` or `EVAL`.
- Abstraction for `SCAN`, `SSCAN`, `ZSCAN` and `HSCAN` (Redis >= 2.8) based on PHP iterators.
- Connections are established lazily by the client upon the first command and can be persisted.
- Connections can be established via TCP/IP (also TLS/SSL-encrypted) or UNIX domain sockets.
- Support for custom connection classes for providing different network or protocol backends.
- Flexible system for defining custom commands and override the default ones.


## How to _install_ and use Predis ##

This library can be found on [Packagist](http://packagist.org/packages/predis/predis) for an easier
management of projects dependencies using [Composer](http://packagist.org/about-composer).
Compressed archives of each release are [available on GitHub](https://github.com/predis/predis/releases).

```shell
composer require predis/predis
```


### Loading the library ###

Predis relies on the autoloading features of PHP to load its files when needed and complies with the
[PSR-4 standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md).
Autoloading is handled automatically when dependencies are managed through Composer, but it is also
possible to leverage its own autoloader in projects or scripts lacking any autoload facility:

```php
// Prepend a base path if Predis is not available in your "include_path".
require 'Predis/Autoloader.php';

Predis\Autoloader::register();
```


### Connecting to Redis ###

When creating a client instance without passing any connection parameter, Predis assumes `127.0.0.1`
and `6379` as default host and port. The default timeout for the `connect()` operation is 5 seconds:

```php
$client = new Predis\Client();
$client->set('foo', 'bar');
$value = $client->get('foo');
```

Connection parameters can be supplied either in the form of URI strings or named arrays. The latter
is the preferred way to supply parameters, but URI strings can be useful when parameters are read
from non-structured or partially-structured sources:

```php
// Parameters passed using a named array:
$client = new Predis\Client([
    'scheme' => 'tcp',
    'host'   => '10.0.0.1',
    'port'   => 6379,
]);

// Same set of parameters, passed using an URI string:
$client = new Predis\Client('tcp://10.0.0.1:6379');
```

Password protected servers can be accessed by adding `password` to the parameters set. When ACLs are
enabled on Redis >= 6.0, both `username` and `password` are required for user authentication.

It is also possible to connect to local instances of Redis using UNIX domain sockets, in this case
the parameters must use the `unix` scheme and specify a path for the socket file:

```php
$client = new Predis\Client(['scheme' => 'unix', 'path' => '/path/to/redis.sock']);
$client = new Predis\Client('unix:/path/to/redis.sock');
```

The client can leverage TLS/SSL encryption to connect to secured remote Redis instances without the
need to configure an SSL proxy like stunnel. This can be useful when connecting to nodes running on
various cloud hosting providers. Encryption can be enabled with using the `tls` scheme and an array
of suitable [options](http://php.net/manual/context.ssl.php) passed via the `ssl` parameter:

```php
// Named array of connection parameters:
$client = new Predis\Client([
  'scheme' => 'tls',
  'ssl'    => ['cafile' => 'private.pem', 'verify_peer' => true],
]);

// Same set of parameters, but using an URI string:
$client = new Predis\Client('tls://127.0.0.1?ssl[cafile]=private.pem&ssl[verify_peer]=1');
```

The connection schemes [`redis`](http://www.iana.org/assignments/uri-schemes/prov/redis) (alias of
`tcp`) and [`rediss`](http://www.iana.org/assignments/uri-schemes/prov/rediss) (alias of `tls`) are
also supported, with the difference that URI strings containing these schemes are parsed following
the rules described on their respective IANA provisional registration documents.

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.

Predis can aggregate multiple connections when providing an array of connection parameters and the
appropriate option to instruct the client about how to aggregate them (clustering, replication or a
custom aggregation logic). Named arrays and URI strings can be mixed when providing configurations
for each node:

```php
$client = new Predis\Client([
    'tcp://10.0.0.1?alias=first-node', ['host' => '10.0.0.2', 'alias' => 'second-node'],
], [
    'cluster' => 'predis',
]);
```

See the [aggregate connections](#aggregate-connections) section of this document for more details.

Connections to Redis are lazy meaning that the client connects to a server only if and when needed.
While it is recommended to let the client do its own stuff under the hood, there may be times when
it is still desired to have control of when the connection is opened or closed: this can easily be
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.


### Client configuration ###

Many aspects and behaviors of the client can be configured by passing specific client options to the
second argument of `Predis\Client::__construct()`:

```php
$client = new Predis\Client($parameters, ['prefix' => 'sample:']);
```

Options are managed using a mini DI-alike container and their values can be lazily initialized only
when needed. The client options supported by default in Predis are:

  - `prefix`: prefix string applied to every key found in commands.
  - `exceptions`: whether the client should throw or return responses upon Redis errors.
  - `connections`: list of connection backends or a connection factory instance.
  - `cluster`: specifies a cluster backend (`predis`, `redis` or callable).
  - `replication`: specifies a replication backend (`predis`, `sentinel` or callable).
  - `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.

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.


### Aggregate connections ###

Aggregate connections are the foundation upon which Predis implements clustering and replication and
they are used to group multiple connections to single Redis nodes and hide the specific logic needed
to handle them properly depending on the context. Aggregate connections usually require an array of
connection parameters along with the appropriate client option when creating a new client instance.

#### Cluster ####

Predis can be configured to work in clustering mode with a traditional client-side sharding approach
to create a cluster of independent nodes and distribute the keyspace among them. This approach needs
some sort of external health monitoring of nodes and requires the keyspace to be rebalanced manually
when nodes are added or removed:

```php
$parameters = ['tcp://10.0.0.1', 'tcp://10.0.0.2', 'tcp://10.0.0.3'];
$options    = ['cluster' => 'predis'];

$client = new Predis\Client($parameters);
```

Along with Redis 3.0, a new supervised and coordinated type of clustering was introduced in the form
of [redis-cluster](http://redis.io/topics/cluster-tutorial). This kind of approach uses a different
algorithm to distribute the keyspaces, with Redis nodes coordinating themselves by communicating via
a gossip protocol to handle health status, rebalancing, nodes discovery and request redirection. In
order to connect to a cluster managed by redis-cluster, the client requires a list of its nodes (not
necessarily complete since it will automatically discover new nodes if necessary) and the `cluster`
client options set to `redis`:

```php
$parameters = ['tcp://10.0.0.1', 'tcp://10.0.0.2', 'tcp://10.0.0.3'];
$options    = ['cluster' => 'redis'];

$client = new Predis\Client($parameters, $options);
```

#### Replication ####

The client can be configured to operate in a single master / multiple slaves setup to provide better
service availability. When using replication, Predis recognizes read-only commands and sends them to
a random slave in order to provide some sort of load-balancing and switches to the master as soon as
it detects a command that performs any kind of operation that would end up modifying the keyspace or
the value of a key. Instead of raising a connection error when a slave fails, the client attempts to
fall back to a different slave among the ones provided in the configuration.

The basic configuration needed to use the client in replication mode requires one Redis server to be
identified as the master (this can be done via connection parameters by setting the `role` parameter
to `master`) and one or more slaves (in this case setting `role` to `slave` for slaves is optional):

```php
$parameters = ['tcp://10.0.0.1?role=master', 'tcp://10.0.0.2', 'tcp://10.0.0.3'];
$options    = ['replication' => 'predis'];

$client = new Predis\Client($parameters, $options);
```

The above configuration has a static list of servers and relies entirely on the client's logic, but
it is possible to rely on [`redis-sentinel`](http://redis.io/topics/sentinel) for a more robust HA
environment with sentinel servers acting as a source of authority for clients for service discovery.
The minimum configuration required by the client to work with redis-sentinel is a list of connection
parameters pointing to a bunch of sentinel instances, the `replication` option set to `sentinel` and
the `service` option set to the name of the service:

```php
$sentinels = ['tcp://10.0.0.1', 'tcp://10.0.0.2', 'tcp://10.0.0.3'];
$options   = ['replication' => 'sentinel', 'service' => 'mymaster'];

$client = new Predis\Client($sentinels, $options);
```

If the master and slave nodes are configured to require an authentication from clients, a password
must be provided via the global `parameters` client option. This option can also be used to specify
a different database index. The client options array would then look like this:

```php
$options = [
    'replication' => 'sentinel',
    'service' => 'mymaster',
    'parameters' => [
        'password' => $secretpassword,
        'database' => 10,
    ],
];
```

While Predis is able to distinguish commands performing write and read-only operations, `EVAL` and
`EVALSHA` represent a corner case in which the client switches to the master node because it cannot
tell when a Lua script is safe to be executed on slaves. While this is indeed the default behavior,
when certain Lua scripts do not perform write operations it is possible to provide an hint to tell
the client to stick with slaves for their execution:

```php
$parameters = ['tcp://10.0.0.1?role=master', 'tcp://10.0.0.2', 'tcp://10.0.0.3'];
$options    = ['replication' => function () {
    // Set scripts that won't trigger a switch from a slave to the master node.
    $strategy = new Predis\Replication\ReplicationStrategy();
    $strategy->setScriptReadOnly($LUA_SCRIPT);

    return new Predis\Connection\Replication\MasterSlaveReplication($strategy);
}];

$client = new Predis\Client($parameters, $options);
$client->eval($LUA_SCRIPT, 0);             // Sticks to slave using `eval`...
$client->evalsha(sha1($LUA_SCRIPT), 0);    // ... and `evalsha`, too.
```

The [`examples`](examples/) directory contains a few scripts that demonstrate how the client can be
configured and used to leverage replication in both basic and complex scenarios.


### Command pipelines ###

Pipelining can help with performances when many commands need to be sent to a server by reducing the
latency introduced by network round-trip timings. Pipelining also works with aggregate connections.
The client can execute the pipeline inside a callable block or return a pipeline instance with the
ability to chain commands thanks to its fluent interface:

```php
// Executes a pipeline inside the given callable block:
$responses = $client->pipeline(function ($pipe) {
    for ($i = 0; $i < 1000; $i++) {
        $pipe->set("key:$i", str_pad($i, 4, '0', 0));
        $pipe->get("key:$i");
    }
});

// Returns a pipeline that can be chained thanks to its fluent interface:
$responses = $client->pipeline()->set('foo', 'bar')->get('foo')->execute();
```


### Transactions ###

The client provides an abstraction for Redis transactions based on `MULTI` and `EXEC` with a similar
interface to command pipelines:

```php
// Executes a transaction inside the given callable block:
$responses = $client->transaction(function ($tx) {
    $tx->set('foo', 'bar');
    $tx->get('foo');
});

// Returns a transaction that can be chained thanks to its fluent interface:
$responses = $client->transaction()->set('foo', 'bar')->get('foo')->execute();
```

This abstraction can perform check-and-set operations thanks to `WATCH` and `UNWATCH` and provides
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).


### Adding new commands ###

While we try to update Predis to stay up to date with all the commands available in Redis, you might
prefer to stick with an old version of the library or provide a different way to filter arguments or
parse responses for specific commands. To achieve that, Predis provides the ability to implement new
command classes to define or override commands in the default command factory used by the client:

```php
// Define a new command by extending Predis\Command\Command:
class BrandNewRedisCommand extends Predis\Command\Command
{
    public function getId()
    {
        return 'NEWCMD';
    }
}

// Inject your command in the current command factory:
$client = new Predis\Client($parameters, [
    'commands' => [
        'newcmd' => 'BrandNewRedisCommand',
    ],
]);

$response = $client->newcmd();
```

There is also a method to send raw commands without filtering their arguments or parsing responses.
Users must provide the list of arguments for the command as an array, following the signatures as
defined by the [Redis documentation for commands](http://redis.io/commands):

```php
$response = $client->executeRaw(['SET', 'foo', 'bar']);
```


### Script commands ###

While it is possible to leverage [Lua scripting](http://redis.io/commands/eval) on Redis 2.6+ using
directly [`EVAL`](http://redis.io/commands/eval) and [`EVALSHA`](http://redis.io/commands/evalsha),
Predis offers script commands as an higher level abstraction built upon them to make things simple.
Script commands can be registered in the command factory used by the client and are accessible as if
they were plain Redis commands, but they define Lua scripts that get transmitted to the server for
remote execution. Internally they use [`EVALSHA`](http://redis.io/commands/evalsha) by default and
identify a script by its SHA1 hash to save bandwidth, but [`EVAL`](http://redis.io/commands/eval)
is used as a fall back when needed:

```php
// Define a new script command by extending Predis\Command\ScriptCommand:
class ListPushRandomValue extends Predis\Command\ScriptCommand
{
    public function getKeysCount()
    {
        return 1;
    }

    public function getScript()
    {
        return <<<LUA
math.randomseed(ARGV[1])
local rnd = tostring(math.random())
redis.call('lpush', KEYS[1], rnd)
return rnd
LUA;
    }
}

// Inject the script command in the current command factory:
$client = new Predis\Client($parameters, [
    'commands' => [
        'lpushrand' => 'ListPushRandomValue',
    ],
]);

$response = $client->lpushrand('random_values', $seed = mt_rand());
```


### Customizable connection backends ###

Predis can use different connection backends to connect to Redis. The builtin Relay integration
leverages the [Relay](https://github.com/cachewerk/relay) extension for PHP for major performance
gains, by caching a partial replica of the Redis dataset in PHP shared runtime memory.

```php
$client = new Predis\Client('tcp://127.0.0.1', [
    'connections' => 'relay',
]);
```

Developers can create their own connection classes to support whole new network backends, extend
existing classes or provide completely different implementations. Connection classes must implement
`Predis\Connection\NodeConnectionInterface` or extend `Predis\Connection\AbstractConnection`:

```php
class MyConnectionClass implements Predis\Connection\NodeConnectionInterface
{
    // Implementation goes here...
}

// Use MyConnectionClass to handle connections for the `tcp` scheme:
$client = new Predis\Client('tcp://127.0.0.1', [
    'connections' => ['tcp' => 'MyConnectionClass'],
]);
```

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.


## Development ##


### Reporting bugs and contributing code ###

Contributions to Predis are highly appreciated either in the form of pull requests for new features,
bug fixes, or just bug reports. We only ask you to adhere to issue and pull request templates.


### Test suite ###

__ATTENTION__: Do not ever run the test suite shipped with Predis against instances of Redis running
in production environments or containing data you are interested in!

Predis has a comprehensive test suite covering every aspect of the library and that can optionally
perform integration tests against a running instance of Redis (required >= 2.4.0 in order to verify
the correct behavior of the implementation of each command. Integration tests for unsupported Redis
commands are automatically skipped. If you do not have Redis up and running, integration tests can
be disabled. See [the tests README](tests/README.md) for more details about testing this library.

Predis uses GitHub Actions for continuous integration and the history for past and current builds can be
found [on its actions page](https://github.com/predis/predis/actions).

### License ###

The code for Predis is distributed under the terms of the MIT license (see [LICENSE](LICENSE)).

[ico-license]: https://img.shields.io/github/license/predis/predis.svg?style=flat-square
[ico-version-stable]: https://img.shields.io/github/v/tag/predis/predis?label=stable&style=flat-square
[ico-version-dev]: https://img.shields.io/github/v/tag/predis/predis?include_prereleases&label=pre-release&style=flat-square
[ico-downloads-monthly]: https://img.shields.io/packagist/dm/predis/predis.svg?style=flat-square
[ico-build]: https://img.shields.io/github/actions/workflow/status/predis/predis/tests.yml?branch=main&style=flat-square
[ico-coverage]: https://img.shields.io/coverallsCoverage/github/predis/predis?style=flat-square

[link-releases]: https://github.com/predis/predis/releases
[link-actions]: https://github.com/predis/predis/actions
[link-downloads]: https://packagist.org/packages/predis/predis/stats
[link-coverage]: https://coveralls.io/github/predis/predis
                                            predis/autoload.php                                                                                 0000644                 00000000404 15233650113 0010350 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

require __DIR__.'/src/Autoloader.php';

Predis\Autoloader::register();
                                                                                                                                                                                                                                                            predis/LICENSE                                                                                      0000644                 00000002174 15233650113 0007042 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       MIT License

Copyright (c) 2009-2020 Daniele Alessandri (original work)
Copyright (c) 2021-2023 Till Krüss (modified work)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
                                                                                                                                                                                                                                                                                                                                                                                                    predis/src/Client.php                                                                               0000644                 00000044506 15233650113 0010560 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis;

use ArrayIterator;
use InvalidArgumentException;
use IteratorAggregate;
use Predis\Command\CommandInterface;
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\ConnectionInterface;
use Predis\Connection\Parameters;
use Predis\Connection\ParametersInterface;
use Predis\Connection\RelayConnection;
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 Traversable;

/**
 * Client class used for connecting and executing commands on Redis.
 *
 * This is the main high-level abstraction of Predis upon which various other
 * abstractions are built. Internally it aggregates various other classes each
 * one with its own responsibility and scope.
 *
 * @template-implements \IteratorAggregate<string, static>
 */
class Client implements ClientInterface, IteratorAggregate
{
    public const VERSION = '2.2.2';

    /** @var OptionsInterface */
    private $options;

    /** @var ConnectionInterface */
    private $connection;

    /** @var Command\FactoryInterface */
    private $commands;

    /**
     * @param mixed $parameters Connection parameters for one or more servers.
     * @param mixed $options    Options to configure some behaviours of the client.
     */
    public function __construct($parameters = null, $options = null)
    {
        $this->options = static::createOptions($options ?? new Options());
        $this->connection = static::createConnection($this->options, $parameters ?? new Parameters());
        $this->commands = $this->options->commands;
    }

    /**
     * Creates a new set of client options for the client.
     *
     * @param array|OptionsInterface $options Set of client options
     *
     * @return OptionsInterface
     * @throws InvalidArgumentException
     */
    protected static function createOptions($options)
    {
        if (is_array($options)) {
            return new Options($options);
        } elseif ($options instanceof OptionsInterface) {
            return $options;
        } else {
            throw new InvalidArgumentException('Invalid type for client options');
        }
    }

    /**
     * Creates single or aggregate connections from supplied arguments.
     *
     * This method accepts the following types to create a connection instance:
     *
     *  - Array (dictionary: single connection, indexed: aggregate connections)
     *  - String (URI for a single connection)
     *  - Callable (connection initializer callback)
     *  - Instance of Predis\Connection\ParametersInterface (used as-is)
     *  - Instance of Predis\Connection\ConnectionInterface (returned as-is)
     *
     * When a callable is passed, it receives the original set of client options
     * and must return an instance of Predis\Connection\ConnectionInterface.
     *
     * Connections are created using the connection factory (in case of single
     * connections) or a specialized aggregate connection initializer (in case
     * of cluster and replication) retrieved from the supplied client options.
     *
     * @param OptionsInterface $options    Client options container
     * @param mixed            $parameters Connection parameters
     *
     * @return ConnectionInterface
     * @throws InvalidArgumentException
     */
    protected static function createConnection(OptionsInterface $options, $parameters)
    {
        if ($parameters instanceof ConnectionInterface) {
            return $parameters;
        }

        if ($parameters instanceof ParametersInterface || is_string($parameters)) {
            return $options->connections->create($parameters);
        }

        if (is_array($parameters)) {
            if (!isset($parameters[0])) {
                return $options->connections->create($parameters);
            } elseif ($options->defined('cluster') && $initializer = $options->cluster) {
                return $initializer($parameters, true);
            } elseif ($options->defined('replication') && $initializer = $options->replication) {
                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'
                );
            }
        }

        if (is_callable($parameters)) {
            $connection = call_user_func($parameters, $options);

            if (!$connection instanceof ConnectionInterface) {
                throw new InvalidArgumentException('Callable parameters must return a valid connection');
            }

            return $connection;
        }

        throw new InvalidArgumentException('Invalid type for connection parameters');
    }

    /**
     * {@inheritdoc}
     */
    public function getCommandFactory()
    {
        return $this->commands;
    }

    /**
     * {@inheritdoc}
     */
    public function getOptions()
    {
        return $this->options;
    }

    /**
     * Creates a new client using a specific underlying connection.
     *
     * This method allows to create a new client instance by picking a specific
     * connection out of an aggregate one, with the same options of the original
     * client instance.
     *
     * The specified selector defines which logic to use to look for a suitable
     * connection by the specified value. Supported selectors are:
     *
     *   - `id`
     *   - `key`
     *   - `slot`
     *   - `command`
     *   - `alias`
     *   - `role`
     *
     * Internally the client relies on duck-typing and follows this convention:
     *
     *   $selector string => getConnectionBy$selector($value) method
     *
     * This means that support for specific selectors may vary depending on the
     * actual logic implemented by connection classes and there is no interface
     * binding a connection class to implement any of these.
     *
     * @param string $selector Type of selector.
     * @param mixed  $value    Value to be used by the selector.
     *
     * @return ClientInterface
     */
    public function getClientBy($selector, $value)
    {
        $selector = strtolower($selector);

        if (!in_array($selector, ['id', 'key', 'slot', 'role', 'alias', 'command'])) {
            throw new InvalidArgumentException("Invalid selector type: `$selector`");
        }

        if (!method_exists($this->connection, $method = "getConnectionBy$selector")) {
            $class = get_class($this->connection);
            throw new InvalidArgumentException("Selecting connection by $selector is not supported by $class");
        }

        if (!$connection = $this->connection->$method($value)) {
            throw new InvalidArgumentException("Cannot find a connection by $selector matching `$value`");
        }

        return new static($connection, $this->getOptions());
    }

    /**
     * Opens the underlying connection and connects to the server.
     */
    public function connect()
    {
        $this->connection->connect();
    }

    /**
     * Closes the underlying connection and disconnects from the server.
     */
    public function disconnect()
    {
        $this->connection->disconnect();
    }

    /**
     * Closes the underlying connection and disconnects from the server.
     *
     * This is the same as `Client::disconnect()` as it does not actually send
     * the `QUIT` command to Redis, but simply closes the connection.
     */
    public function quit()
    {
        $this->disconnect();
    }

    /**
     * Returns the current state of the underlying connection.
     *
     * @return bool
     */
    public function isConnected()
    {
        return $this->connection->isConnected();
    }

    /**
     * {@inheritdoc}
     */
    public function getConnection()
    {
        return $this->connection;
    }

    /**
     * Applies the configured serializer and compression to given value.
     *
     * @param  mixed  $value
     * @return string
     */
    public function pack($value)
    {
        return $this->connection instanceof RelayConnection
            ? $this->connection->pack($value)
            : $value;
    }

    /**
     * Deserializes and decompresses to given value.
     *
     * @param  mixed  $value
     * @return string
     */
    public function unpack($value)
    {
        return $this->connection instanceof RelayConnection
            ? $this->connection->unpack($value)
            : $value;
    }

    /**
     * Executes a command without filtering its arguments, parsing the response,
     * applying any prefix to keys or throwing exceptions on Redis errors even
     * regardless of client options.
     *
     * It is possible to identify Redis error responses from normal responses
     * using the second optional argument which is populated by reference.
     *
     * @param array $arguments Command arguments as defined by the command signature.
     * @param bool  $error     Set to TRUE when Redis returned an error response.
     *
     * @return mixed
     */
    public function executeRaw(array $arguments, &$error = null)
    {
        $error = false;
        $commandID = array_shift($arguments);

        $response = $this->connection->executeCommand(
            new RawCommand($commandID, $arguments)
        );

        if ($response instanceof ResponseInterface) {
            if ($response instanceof ErrorResponseInterface) {
                $error = true;
            }

            return (string) $response;
        }

        return $response;
    }

    /**
     * {@inheritdoc}
     */
    public function __call($commandID, $arguments)
    {
        return $this->executeCommand(
            $this->createCommand($commandID, $arguments)
        );
    }

    /**
     * {@inheritdoc}
     */
    public function createCommand($commandID, $arguments = [])
    {
        return $this->commands->create($commandID, $arguments);
    }

    /**
     * @param  string             $name
     * @return ContainerInterface
     */
    public function __get(string $name)
    {
        return ContainerFactory::create($this, $name);
    }

    /**
     * @param  string $name
     * @param  mixed  $value
     * @return mixed
     */
    public function __set(string $name, $value)
    {
        throw new RuntimeException('Not allowed');
    }

    /**
     * @param  string $name
     * @return mixed
     */
    public function __isset(string $name)
    {
        throw new RuntimeException('Not allowed');
    }

    /**
     * {@inheritdoc}
     */
    public function executeCommand(CommandInterface $command)
    {
        $response = $this->connection->executeCommand($command);

        if ($response instanceof ResponseInterface) {
            if ($response instanceof ErrorResponseInterface) {
                $response = $this->onErrorResponse($command, $response);
            }

            return $response;
        }

        return $command->parseResponse($response);
    }

    /**
     * Handles -ERR responses returned by Redis.
     *
     * @param CommandInterface       $command  Redis command that generated the error.
     * @param ErrorResponseInterface $response Instance of the error response.
     *
     * @return mixed
     * @throws ServerException
     */
    protected function onErrorResponse(CommandInterface $command, ErrorResponseInterface $response)
    {
        if ($command instanceof ScriptCommand && $response->getErrorType() === 'NOSCRIPT') {
            $response = $this->executeCommand($command->getEvalCommand());

            if (!$response instanceof ResponseInterface) {
                $response = $command->parseResponse($response);
            }

            return $response;
        }

        if ($this->options->exceptions) {
            throw new ServerException($response->getMessage());
        }

        return $response;
    }

    /**
     * Executes the specified initializer method on `$this` by adjusting the
     * actual invocation depending on the arity (0, 1 or 2 arguments). This is
     * simply an utility method to create Redis contexts instances since they
     * follow a common initialization path.
     *
     * @param string $initializer Method name.
     * @param array  $argv        Arguments for the method.
     *
     * @return mixed
     */
    private function sharedContextFactory($initializer, $argv = null)
    {
        switch (count($argv)) {
            case 0:
                return $this->$initializer();

            case 1:
                return is_array($argv[0])
                    ? $this->$initializer($argv[0])
                    : $this->$initializer(null, $argv[0]);

            case 2:
                [$arg0, $arg1] = $argv;

                return $this->$initializer($arg0, $arg1);

            default:
                return $this->$initializer($this, $argv);
        }
    }

    /**
     * Creates a new pipeline context and returns it, or returns the results of
     * a pipeline executed inside the optionally provided callable object.
     *
     * @param mixed ...$arguments Array of options, a callable for execution, or both.
     *
     * @return Pipeline|array
     */
    public function pipeline(...$arguments)
    {
        return $this->sharedContextFactory('createPipeline', func_get_args());
    }

    /**
     * Actual pipeline context initializer method.
     *
     * @param array|null $options  Options for the context.
     * @param mixed      $callable Optional callable used to execute the context.
     *
     * @return Pipeline|array
     */
    protected function createPipeline(array $options = null, $callable = null)
    {
        if (isset($options['atomic']) && $options['atomic']) {
            $class = Atomic::class;
        } elseif (isset($options['fire-and-forget']) && $options['fire-and-forget']) {
            $class = FireAndForget::class;
        } else {
            $class = Pipeline::class;
        }

        if ($this->connection instanceof RelayConnection) {
            if (isset($options['atomic']) && $options['atomic']) {
                $class = RelayAtomic::class;
            } elseif (isset($options['fire-and-forget']) && $options['fire-and-forget']) {
                throw new NotSupportedException('The "relay" extension does not support fire-and-forget pipelines.');
            } else {
                $class = RelayPipeline::class;
            }
        }

        /*
         * @var ClientContextInterface
         */
        $pipeline = new $class($this);

        if (isset($callable)) {
            return $pipeline->execute($callable);
        }

        return $pipeline;
    }

    /**
     * Creates a new transaction context and returns it, or returns the results
     * of a transaction executed inside the optionally provided callable object.
     *
     * @param mixed ...$arguments Array of options, a callable for execution, or both.
     *
     * @return MultiExecTransaction|array
     */
    public function transaction(...$arguments)
    {
        return $this->sharedContextFactory('createTransaction', func_get_args());
    }

    /**
     * Actual transaction context initializer method.
     *
     * @param array $options  Options for the context.
     * @param mixed $callable Optional callable used to execute the context.
     *
     * @return MultiExecTransaction|array
     */
    protected function createTransaction(array $options = null, $callable = null)
    {
        $transaction = new MultiExecTransaction($this, $options);

        if (isset($callable)) {
            return $transaction->execute($callable);
        }

        return $transaction;
    }

    /**
     * Creates a new publish/subscribe context and returns it, or starts its loop
     * inside the optionally provided callable object.
     *
     * @param mixed ...$arguments Array of options, a callable for execution, or both.
     *
     * @return PubSubConsumer|null
     */
    public function pubSubLoop(...$arguments)
    {
        return $this->sharedContextFactory('createPubSub', func_get_args());
    }

    /**
     * Actual publish/subscribe context initializer method.
     *
     * @param array $options  Options for the context.
     * @param mixed $callable Optional callable used to execute the context.
     *
     * @return PubSubConsumer|null
     */
    protected function createPubSub(array $options = null, $callable = null)
    {
        if ($this->connection instanceof RelayConnection) {
            $pubsub = new RelayPubSubConsumer($this, $options);
        } else {
            $pubsub = new PubSubConsumer($this, $options);
        }

        if (!isset($callable)) {
            return $pubsub;
        }

        foreach ($pubsub as $message) {
            if (call_user_func($callable, $pubsub, $message) === false) {
                $pubsub->stop();
            }
        }

        return null;
    }

    /**
     * Creates a new monitor consumer and returns it.
     *
     * @return MonitorConsumer
     */
    public function monitor()
    {
        return new MonitorConsumer($this);
    }

    /**
     * @return Traversable<string, static>
     */
    #[ReturnTypeWillChange]
    public function getIterator()
    {
        $clients = [];
        $connection = $this->getConnection();

        if (!$connection instanceof Traversable) {
            return new ArrayIterator([
                (string) $connection => new static($connection, $this->getOptions()),
            ]);
        }

        foreach ($connection as $node) {
            $clients[(string) $node] = new static($node, $this->getOptions());
        }

        return new ArrayIterator($clients);
    }
}
                                                                                                                                                                                          predis/src/ClientContextInterface.php                                                               0000644                 00000050307 15233650113 0013742 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis;

use Predis\Command\Argument\Geospatial\ByInterface;
use Predis\Command\Argument\Geospatial\FromInterface;
use Predis\Command\Argument\Search\AggregateArguments;
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\ProfileArguments;
use Predis\Command\Argument\Search\SchemaFields\FieldInterface;
use Predis\Command\Argument\Search\SearchArguments;
use Predis\Command\Argument\Search\SugAddArguments;
use Predis\Command\Argument\Search\SugGetArguments;
use Predis\Command\Argument\Search\SynUpdateArguments;
use Predis\Command\Argument\Server\LimitOffsetCount;
use Predis\Command\Argument\Server\To;
use Predis\Command\Argument\TimeSeries\AddArguments;
use Predis\Command\Argument\TimeSeries\AlterArguments as TSAlterArguments;
use Predis\Command\Argument\TimeSeries\CreateArguments as TSCreateArguments;
use Predis\Command\Argument\TimeSeries\DecrByArguments;
use Predis\Command\Argument\TimeSeries\GetArguments;
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\RangeArguments;
use Predis\Command\CommandInterface;
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 dump($key)
 * @method $this exists($key)
 * @method $this expire($key, $seconds, string $expireOption = '')
 * @method $this expireat($key, $timestamp, string $expireOption = '')
 * @method $this expiretime(string $key)
 * @method $this keys($pattern)
 * @method $this move($key, $db)
 * @method $this object($subcommand, $key)
 * @method $this persist($key)
 * @method $this pexpire($key, $milliseconds)
 * @method $this pexpireat($key, $timestamp)
 * @method $this pttl($key)
 * @method $this randomkey()
 * @method $this rename($key, $target)
 * @method $this renamenx($key, $target)
 * @method $this scan($cursor, array $options = null)
 * @method $this sort($key, array $options = null)
 * @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 append($key, $value)
 * @method $this bfadd(string $key, $item)
 * @method $this bfexists(string $key, $item)
 * @method $this bfinfo(string $key, string $modifier = '')
 * @method $this bfinsert(string $key, int $capacity = -1, float $error = -1, int $expansion = -1, bool $noCreate = false, bool $nonScaling = false, string ...$item)
 * @method $this bfloadchunk(string $key, int $iterator, $data)
 * @method $this bfmadd(string $key, ...$item)
 * @method $this bfmexists(string $key, ...$item)
 * @method $this bfreserve(string $key, float $errorRate, int $capacity, int $expansion = -1, bool $nonScaling = false)
 * @method $this bfscandump(string $key, int $iterator)
 * @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 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)
 * @method $this bzpopmin(array $keys, int $timeout)
 * @method $this bzmpop(int $timeout, array $keys, string $modifier = 'min', int $count = 1)
 * @method $this cfadd(string $key, $item)
 * @method $this cfaddnx(string $key, $item)
 * @method $this cfcount(string $key, $item)
 * @method $this cfdel(string $key, $item)
 * @method $this cfexists(string $key, $item)
 * @method $this cfloadchunk(string $key, int $iterator, $data)
 * @method $this cfmexists(string $key, ...$item)
 * @method $this cfinfo(string $key)
 * @method $this cfinsert(string $key, int $capacity = -1, bool $noCreate = false, string ...$item)
 * @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 cmsinfo(string $key)
 * @method $this cmsinitbydim(string $key, int $width, int $depth)
 * @method $this cmsinitbyprob(string $key, float $errorRate, float $probability)
 * @method $this cmsmerge(string $destination, array $sources, array $weights = [])
 * @method $this cmsquery(string $key, string ...$item)
 * @method $this decr($key)
 * @method $this decrby($key, $decrement)
 * @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 ftaggregate(string $index, string $query, ?AggregateArguments $arguments = null)
 * @method $this ftaliasadd(string $alias, string $index)
 * @method $this ftaliasdel(string $alias)
 * @method $this ftaliasupdate(string $alias, string $index)
 * @method $this ftalter(string $index, FieldInterface[] $schema, ?AlterArguments $arguments = null)
 * @method $this ftcreate(string $index, FieldInterface[] $schema, ?CreateArguments $arguments = null)
 * @method $this ftdictadd(string $dict, ...$term)
 * @method $this ftdictdel(string $dict, ...$term)
 * @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 ftinfo(string $index)
 * @method $this ftprofile(string $index, ProfileArguments $arguments)
 * @method $this ftsearch(string $index, string $query, ?SearchArguments $arguments = null)
 * @method $this ftspellcheck(string $index, string $query, ?SearchArguments $arguments = null)
 * @method $this ftsugadd(string $key, string $string, float $score, ?SugAddArguments $arguments = null)
 * @method $this ftsugdel(string $key, string $string)
 * @method $this ftsugget(string $key, string $prefix, ?SugGetArguments $arguments = null)
 * @method $this ftsuglen(string $key)
 * @method $this ftsyndump(string $index)
 * @method $this ftsynupdate(string $index, string $synonymGroupId, ?SynUpdateArguments $arguments = null, string ...$terms)
 * @method $this fttagvals(string $index, string $fieldName)
 * @method $this get($key)
 * @method $this getbit($key, $offset)
 * @method $this getex(string $key, $modifier = '', $value = false)
 * @method $this getrange($key, $start, $end)
 * @method $this getdel(string $key)
 * @method $this getset($key, $value)
 * @method $this incr($key)
 * @method $this incrby($key, $increment)
 * @method $this incrbyfloat($key, $increment)
 * @method $this mget(array $keys)
 * @method $this mset(array $dictionary)
 * @method $this msetnx(array $dictionary)
 * @method $this psetex($key, $milliseconds, $value)
 * @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)
 * @method $this setrange($key, $offset, $value)
 * @method $this strlen($key)
 * @method $this hdel($key, array $fields)
 * @method $this hexists($key, $field)
 * @method $this hget($key, $field)
 * @method $this hgetall($key)
 * @method $this hincrby($key, $field, $increment)
 * @method $this hincrbyfloat($key, $field, $increment)
 * @method $this hkeys($key)
 * @method $this hlen($key)
 * @method $this hmget($key, array $fields)
 * @method $this hmset($key, array $dictionary)
 * @method $this hrandfield(string $key, int $count = 1, bool $withValues = false)
 * @method $this hscan($key, $cursor, array $options = null)
 * @method $this hset($key, $field, $value)
 * @method $this hsetnx($key, $field, $value)
 * @method $this hvals($key)
 * @method $this hstrlen($key, $field)
 * @method $this jsonarrappend(string $key, string $path = '$', ...$value)
 * @method $this jsonarrindex(string $key, string $path, string $value, int $start = 0, int $stop = 0)
 * @method $this jsonarrinsert(string $key, string $path, int $index, string ...$value)
 * @method $this jsonarrlen(string $key, string $path = '$')
 * @method $this jsonarrpop(string $key, string $path = '$', int $index = -1)
 * @method $this jsonarrtrim(string $key, string $path, int $start, int $stop)
 * @method $this jsonclear(string $key, string $path = '$')
 * @method $this jsondel(string $key, string $path = '$')
 * @method $this jsonforget(string $key, string $path = '$')
 * @method $this jsonget(string $key, string $indent = '', string $newline = '', string $space = '', string ...$paths)
 * @method $this jsonnumincrby(string $key, string $path, int $value)
 * @method $this jsonmerge(string $key, string $path, string $value)
 * @method $this jsonmget(array $keys, string $path)
 * @method $this jsonmset(string ...$keyPathValue)
 * @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)
 * @method $this jsonstrappend(string $key, string $path, string $value)
 * @method $this jsonstrlen(string $key, string $path = '$')
 * @method $this jsontoggle(string $key, string $path)
 * @method $this jsontype(string $key, string $path = '$')
 * @method $this blmove(string $source, string $destination, string $where, string $to, int $timeout)
 * @method $this blpop(array|string $keys, $timeout)
 * @method $this brpop(array|string $keys, $timeout)
 * @method $this brpoplpush($source, $destination, $timeout)
 * @method $this lcs(string $key1, string $key2, bool $len = false, bool $idx = false, int $minMatchLen = 0, bool $withMatchLen = false)
 * @method $this lindex($key, $index)
 * @method $this linsert($key, $whence, $pivot, $value)
 * @method $this llen($key)
 * @method $this lmove(string $source, string $destination, string $where, string $to)
 * @method $this lmpop(array $keys, string $modifier = 'left', int $count = 1)
 * @method $this lpop($key)
 * @method $this lpush($key, array $values)
 * @method $this lpushx($key, array $values)
 * @method $this lrange($key, $start, $stop)
 * @method $this lrem($key, $count, $value)
 * @method $this lset($key, $index, $value)
 * @method $this ltrim($key, $start, $stop)
 * @method $this rpop($key)
 * @method $this rpoplpush($source, $destination)
 * @method $this rpush($key, array $values)
 * @method $this rpushx($key, array $values)
 * @method $this sadd($key, array $members)
 * @method $this scard($key)
 * @method $this sdiff(array|string $keys)
 * @method $this sdiffstore($destination, array|string $keys)
 * @method $this sinter(array|string $keys)
 * @method $this sintercard(array $keys, int $limit = 0)
 * @method $this sinterstore($destination, array|string $keys)
 * @method $this sismember($key, $member)
 * @method $this smembers($key)
 * @method $this smismember(string $key, string ...$members)
 * @method $this smove($source, $destination, $member)
 * @method $this spop($key, $count = null)
 * @method $this srandmember($key, $count = null)
 * @method $this srem($key, $member)
 * @method $this sscan($key, $cursor, array $options = null)
 * @method $this sunion(array|string $keys)
 * @method $this sunionstore($destination, array|string $keys)
 * @method $this tdigestadd(string $key, float ...$value)
 * @method $this tdigestbyrank(string $key, int ...$rank)
 * @method $this tdigestbyrevrank(string $key, int ...$reverseRank)
 * @method $this tdigestcdf(string $key, int ...$value)
 * @method $this tdigestcreate(string $key, int $compression = 0)
 * @method $this tdigestinfo(string $key)
 * @method $this tdigestmax(string $key)
 * @method $this tdigestmerge(string $destinationKey, array $sourceKeys, int $compression = 0, bool $override = false)
 * @method $this tdigestquantile(string $key, float ...$quantile)
 * @method $this tdigestmin(string $key)
 * @method $this tdigestrank(string $key, ...$value)
 * @method $this tdigestreset(string $key)
 * @method $this tdigestrevrank(string $key, float ...$value)
 * @method $this tdigesttrimmed_mean(string $key, float $lowCutQuantile, float $highCutQuantile)
 * @method $this topkadd(string $key, ...$items)
 * @method $this topkincrby(string $key, ...$itemIncrement)
 * @method $this topkinfo(string $key)
 * @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, 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)
 * @method $this tsdecrby(string $key, float $value, ?DecrByArguments $arguments = null)
 * @method $this tsdel(string $key, int $fromTimestamp, int $toTimestamp)
 * @method $this tsdeleterule(string $sourceKey, string $destKey)
 * @method $this tsget(string $key, GetArguments $arguments = null)
 * @method $this tsincrby(string $key, float $value, ?IncrByArguments $arguments = null)
 * @method $this tsinfo(string $key, ?InfoArguments $arguments = null)
 * @method $this tsmadd(mixed ...$keyTimestampValue)
 * @method $this tsmget(MGetArguments $arguments, string ...$filterExpression)
 * @method $this tsmrange($fromTimestamp, $toTimestamp, MRangeArguments $arguments)
 * @method $this tsmrevrange($fromTimestamp, $toTimestamp, MRangeArguments $arguments)
 * @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 zadd($key, array $membersAndScoresDictionary)
 * @method $this zcard($key)
 * @method $this zcount($key, $min, $max)
 * @method $this zdiff(array $keys, bool $withScores = false)
 * @method $this zdiffstore(string $destination, array $keys)
 * @method $this zincrby($key, $increment, $member)
 * @method $this zintercard(array $keys, int $limit = 0)
 * @method $this zinterstore(string $destination, array $keys, int[] $weights = [], string $aggregate = 'sum')
 * @method $this zinter(array $keys, int[] $weights = [], string $aggregate = 'sum', bool $withScores = false)
 * @method $this zmpop(array $keys, string $modifier = 'min', int $count = 1)
 * @method $this zmscore(string $key, string ...$member)
 * @method $this zrandmember(string $key, int $count = 1, bool $withScores = false)
 * @method $this zrange($key, $start, $stop, array $options = null)
 * @method $this zrangebyscore($key, $min, $max, array $options = null)
 * @method $this zrangestore(string $destination, string $source, int|string $min, string|int $max, string|bool $by = false, bool $reversed = false, bool $limit = false, int $offset = 0, int $count = 0)
 * @method $this zrank($key, $member)
 * @method $this zrem($key, $member)
 * @method $this zremrangebyrank($key, $start, $stop)
 * @method $this zremrangebyscore($key, $min, $max)
 * @method $this zrevrange($key, $start, $stop, array $options = null)
 * @method $this zrevrangebyscore($key, $max, $min, array $options = null)
 * @method $this zrevrank($key, $member)
 * @method $this zunion(array $keys, int[] $weights = [], string $aggregate = 'sum', bool $withScores = false)
 * @method $this zunionstore(string $destination, array $keys, int[] $weights = [], string $aggregate = 'sum')
 * @method $this zscore($key, $member)
 * @method $this zscan($key, $cursor, array $options = null)
 * @method $this zrangebylex($key, $start, $stop, array $options = null)
 * @method $this zrevrangebylex($key, $start, $stop, array $options = null)
 * @method $this zremrangebylex($key, $min, $max)
 * @method $this zlexcount($key, $min, $max)
 * @method $this pexpiretime(string $key)
 * @method $this pfadd($key, array $elements)
 * @method $this pfmerge($destinationKey, array|string $sourceKeys)
 * @method $this pfcount(array|string $keys)
 * @method $this pubsub($subcommand, $argument)
 * @method $this publish($channel, $message)
 * @method $this discard()
 * @method $this exec()
 * @method $this multi()
 * @method $this unwatch()
 * @method $this waitaof(int $numLocal, int $numReplicas, int $timeout)
 * @method $this watch($key)
 * @method $this eval($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
 * @method $this eval_ro(string $script, array $keys, ...$argument)
 * @method $this evalsha($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
 * @method $this evalsha_ro(string $sha1, array $keys, ...$argument)
 * @method $this script($subcommand, $argument = null)
 * @method $this shutdown(bool $noSave = null, bool $now = false, bool $force = false, bool $abort = false)
 * @method $this auth($password)
 * @method $this echo($message)
 * @method $this ping($message = null)
 * @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($section = null)
 * @method $this lastsave()
 * @method $this save()
 * @method $this slaveof($host, $port)
 * @method $this slowlog($subcommand, $argument = null)
 * @method $this time()
 * @method $this command()
 * @method $this geoadd($key, $longitude, $latitude, $member)
 * @method $this geohash($key, array $members)
 * @method $this geopos($key, array $members)
 * @method $this geodist($key, $member1, $member2, $unit = null)
 * @method $this georadius($key, $longitude, $latitude, $radius, $unit, array $options = null)
 * @method $this georadiusbymember($key, $member, $radius, $unit, array $options = null)
 * @method $this geosearch(string $key, FromInterface $from, ByInterface $by, ?string $sorting = null, int $count = -1, bool $any = false, bool $withCoord = false, bool $withDist = false, bool $withHash = false)
 * @method $this geosearchstore(string $destination, string $source, FromInterface $from, ByInterface $by, ?string $sorting = null, int $count = -1, bool $any = false, bool $storeDist = false)
 *
 * Container commands
 * @property CLUSTER           $cluster
 * @property FunctionContainer $function
 * @property FTCONFIG          $ftconfig
 * @property FTCURSOR          $ftcursor
 * @property JSONDEBUG         $jsondebug
 * @property ACL               $acl
 */
interface ClientContextInterface
{
    /**
     * Sends the specified command instance to Redis.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return mixed
     */
    public function executeCommand(CommandInterface $command);

    /**
     * Sends the specified command with its arguments to Redis.
     *
     * @param string $method    Command ID.
     * @param array  $arguments Arguments for the command.
     *
     * @return mixed
     */
    public function __call($method, $arguments);

    /**
     * Starts the execution of the context.
     *
     * @param mixed $callable Optional callback for execution.
     *
     * @return array
     */
    public function execute($callable = null);
}
                                                                                                                                                                                                                                                                                                                         predis/src/PubSub/AbstractConsumer.php                                                              0000644                 00000013067 15233650113 0014017 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\PubSub;

use Iterator;
use ReturnTypeWillChange;

/**
 * Base implementation of a PUB/SUB consumer abstraction based on PHP iterators.
 */
abstract class AbstractConsumer implements Iterator
{
    public const SUBSCRIBE = 'subscribe';
    public const UNSUBSCRIBE = 'unsubscribe';
    public const PSUBSCRIBE = 'psubscribe';
    public const PUNSUBSCRIBE = 'punsubscribe';
    public const MESSAGE = 'message';
    public const PMESSAGE = 'pmessage';
    public const PONG = 'pong';

    public const STATUS_VALID = 1;       // 0b0001
    public const STATUS_SUBSCRIBED = 2;  // 0b0010
    public const STATUS_PSUBSCRIBED = 4; // 0b0100

    protected $position;
    protected $statusFlags = self::STATUS_VALID;

    /**
     * Automatically stops the consumer when the garbage collector kicks in.
     */
    public function __destruct()
    {
        $this->stop(true);
    }

    /**
     * Checks if the specified flag is valid based on the state of the consumer.
     *
     * @param int $value Flag.
     *
     * @return bool
     */
    protected function isFlagSet($value)
    {
        return ($this->statusFlags & $value) === $value;
    }

    /**
     * Subscribes to the specified channels.
     *
     * @param string ...$channel One or more channel names.
     */
    public function subscribe($channel /* , ... */)
    {
        $this->writeRequest(self::SUBSCRIBE, func_get_args());
        $this->statusFlags |= self::STATUS_SUBSCRIBED;
    }

    /**
     * Unsubscribes from the specified channels.
     *
     * @param string ...$channel One or more channel names.
     */
    public function unsubscribe(...$channel)
    {
        $this->writeRequest(self::UNSUBSCRIBE, func_get_args());
    }

    /**
     * Subscribes to the specified channels using a pattern.
     *
     * @param string ...$pattern One or more channel name patterns.
     */
    public function psubscribe(...$pattern)
    {
        $this->writeRequest(self::PSUBSCRIBE, func_get_args());
        $this->statusFlags |= self::STATUS_PSUBSCRIBED;
    }

    /**
     * Unsubscribes from the specified channels using a pattern.
     *
     * @param string ...$pattern One or more channel name patterns.
     */
    public function punsubscribe(...$pattern)
    {
        $this->writeRequest(self::PUNSUBSCRIBE, func_get_args());
    }

    /**
     * PING the server with an optional payload that will be echoed as a
     * PONG message in the pub/sub loop.
     *
     * @param string $payload Optional PING payload.
     */
    public function ping($payload = null)
    {
        $this->writeRequest('PING', [$payload]);
    }

    /**
     * Closes the context by unsubscribing from all the subscribed channels. The
     * context can be forcefully closed by dropping the underlying connection.
     *
     * @param bool $drop Indicates if the context should be closed by dropping the connection.
     *
     * @return bool Returns false when there are no pending messages.
     */
    public function stop($drop = false)
    {
        if (!$this->valid()) {
            return false;
        }

        if ($drop) {
            $this->invalidate();
            $this->disconnect();
        } else {
            if ($this->isFlagSet(self::STATUS_SUBSCRIBED)) {
                $this->unsubscribe();
            }
            if ($this->isFlagSet(self::STATUS_PSUBSCRIBED)) {
                $this->punsubscribe();
            }
        }

        return !$drop;
    }

    /**
     * Closes the underlying connection when forcing a disconnection.
     */
    abstract protected function disconnect();

    /**
     * Writes a Redis command on the underlying connection.
     *
     * @param string $method    Command ID.
     * @param array  $arguments Arguments for the command.
     */
    abstract protected function writeRequest($method, $arguments);

    /**
     * @return void
     */
    #[ReturnTypeWillChange]
    public function rewind()
    {
        // NOOP
    }

    /**
     * Returns the last message payload retrieved from the server and generated
     * by one of the active subscriptions.
     *
     * @return array
     */
    #[ReturnTypeWillChange]
    public function current()
    {
        return $this->getValue();
    }

    /**
     * @return int|null
     */
    #[ReturnTypeWillChange]
    public function key()
    {
        return $this->position;
    }

    /**
     * @return int|null
     */
    #[ReturnTypeWillChange]
    public function next()
    {
        if ($this->valid()) {
            ++$this->position;
        }

        return $this->position;
    }

    /**
     * Checks if the the consumer is still in a valid state to continue.
     *
     * @return bool
     */
    #[ReturnTypeWillChange]
    public function valid()
    {
        $isValid = $this->isFlagSet(self::STATUS_VALID);
        $subscriptionFlags = self::STATUS_SUBSCRIBED | self::STATUS_PSUBSCRIBED;
        $hasSubscriptions = ($this->statusFlags & $subscriptionFlags) > 0;

        return $isValid && $hasSubscriptions;
    }

    /**
     * Resets the state of the consumer.
     */
    protected function invalidate()
    {
        $this->statusFlags = 0;    // 0b0000;
    }

    /**
     * Waits for a new message from the server generated by one of the active
     * subscriptions and returns it when available.
     *
     * @return array
     */
    abstract protected function getValue();
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                         predis/src/PubSub/Consumer.php                                                                      0000644                 00000010434 15233650113 0012326 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\PubSub;

use Predis\ClientException;
use Predis\ClientInterface;
use Predis\Command\Command;
use Predis\Connection\Cluster\ClusterInterface;
use Predis\NotSupportedException;

/**
 * PUB/SUB consumer.
 */
class Consumer extends AbstractConsumer
{
    protected $client;
    protected $options;

    /**
     * @param ClientInterface $client  Client instance used by the consumer.
     * @param array           $options Options for the consumer initialization.
     */
    public function __construct(ClientInterface $client, array $options = null)
    {
        $this->checkCapabilities($client);

        $this->options = $options ?: [];
        $this->client = $client;

        $this->genericSubscribeInit('subscribe');
        $this->genericSubscribeInit('psubscribe');
    }

    /**
     * Returns the underlying client instance used by the pub/sub iterator.
     *
     * @return ClientInterface
     */
    public function getClient()
    {
        return $this->client;
    }

    /**
     * Checks if the client instance satisfies the required conditions needed to
     * initialize a PUB/SUB consumer.
     *
     * @param ClientInterface $client Client instance used by the consumer.
     *
     * @throws NotSupportedException
     */
    protected function checkCapabilities(ClientInterface $client)
    {
        if ($client->getConnection() instanceof ClusterInterface) {
            throw new NotSupportedException(
                'Cannot initialize a PUB/SUB consumer over cluster connections.'
            );
        }

        $commands = ['publish', 'subscribe', 'unsubscribe', 'psubscribe', 'punsubscribe'];

        if (!$client->getCommandFactory()->supports(...$commands)) {
            throw new NotSupportedException(
                'PUB/SUB commands are not supported by the current command factory.'
            );
        }
    }

    /**
     * This method shares the logic to handle both SUBSCRIBE and PSUBSCRIBE.
     *
     * @param string $subscribeAction Type of subscription.
     */
    protected function genericSubscribeInit($subscribeAction)
    {
        if (isset($this->options[$subscribeAction])) {
            $this->$subscribeAction($this->options[$subscribeAction]);
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function writeRequest($method, $arguments)
    {
        $this->client->getConnection()->writeRequest(
            $this->client->createCommand($method,
                Command::normalizeArguments($arguments)
            )
        );
    }

    /**
     * {@inheritdoc}
     */
    protected function disconnect()
    {
        $this->client->disconnect();
    }

    /**
     * {@inheritdoc}
     */
    protected function getValue()
    {
        $response = $this->client->getConnection()->read();

        switch ($response[0]) {
            case self::SUBSCRIBE:
            case self::UNSUBSCRIBE:
            case self::PSUBSCRIBE:
            case self::PUNSUBSCRIBE:
                if ($response[2] === 0) {
                    $this->invalidate();
                }
                // The missing break here is intentional as we must process
                // subscriptions and unsubscriptions as standard messages.
                // no break

            case self::MESSAGE:
                return (object) [
                    'kind' => $response[0],
                    'channel' => $response[1],
                    'payload' => $response[2],
                ];

            case self::PMESSAGE:
                return (object) [
                    'kind' => $response[0],
                    'pattern' => $response[1],
                    'channel' => $response[2],
                    'payload' => $response[3],
                ];

            case self::PONG:
                return (object) [
                    'kind' => $response[0],
                    'payload' => $response[1],
                ];

            default:
                throw new ClientException(
                    "Unknown message type '{$response[0]}' received in the PUB/SUB context."
                );
        }
    }
}
                                                                                                                                                                                                                                    predis/src/PubSub/DispatcherLoop.php                                                                0000644                 00000010233 15233650113 0013450 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\PubSub;

use InvalidArgumentException;

/**
 * Method-dispatcher loop built around the client-side abstraction of a Redis
 * PUB / SUB context.
 */
class DispatcherLoop
{
    private $pubsub;

    protected $callbacks;
    protected $defaultCallback;
    protected $subscriptionCallback;

    /**
     * @param Consumer $pubsub PubSub consumer instance used by the loop.
     */
    public function __construct(Consumer $pubsub)
    {
        $this->callbacks = [];
        $this->pubsub = $pubsub;
    }

    /**
     * Checks if the passed argument is a valid callback.
     *
     * @param mixed $callable A callback.
     *
     * @throws InvalidArgumentException
     */
    protected function assertCallback($callable)
    {
        if (!is_callable($callable)) {
            throw new InvalidArgumentException('The given argument must be a callable object.');
        }
    }

    /**
     * Returns the underlying PUB / SUB context.
     *
     * @return Consumer
     */
    public function getPubSubConsumer()
    {
        return $this->pubsub;
    }

    /**
     * Sets a callback that gets invoked upon new subscriptions.
     *
     * @param mixed $callable A callback.
     */
    public function subscriptionCallback($callable = null)
    {
        if (isset($callable)) {
            $this->assertCallback($callable);
        }

        $this->subscriptionCallback = $callable;
    }

    /**
     * Sets a callback that gets invoked when a message is received on a
     * channel that does not have an associated callback.
     *
     * @param mixed $callable A callback.
     */
    public function defaultCallback($callable = null)
    {
        if (isset($callable)) {
            $this->assertCallback($callable);
        }

        $this->subscriptionCallback = $callable;
    }

    /**
     * Binds a callback to a channel.
     *
     * @param string   $channel  Channel name.
     * @param callable $callback A callback.
     */
    public function attachCallback($channel, $callback)
    {
        $callbackName = $this->getPrefixKeys() . $channel;

        $this->assertCallback($callback);
        $this->callbacks[$callbackName] = $callback;
        $this->pubsub->subscribe($channel);
    }

    /**
     * Stops listening to a channel and removes the associated callback.
     *
     * @param string $channel Redis channel.
     */
    public function detachCallback($channel)
    {
        $callbackName = $this->getPrefixKeys() . $channel;

        if (isset($this->callbacks[$callbackName])) {
            unset($this->callbacks[$callbackName]);
            $this->pubsub->unsubscribe($channel);
        }
    }

    /**
     * Starts the dispatcher loop.
     */
    public function run()
    {
        foreach ($this->pubsub as $message) {
            $kind = $message->kind;

            if ($kind !== Consumer::MESSAGE && $kind !== Consumer::PMESSAGE) {
                if (isset($this->subscriptionCallback)) {
                    $callback = $this->subscriptionCallback;
                    call_user_func($callback, $message, $this);
                }

                continue;
            }

            if (isset($this->callbacks[$message->channel])) {
                $callback = $this->callbacks[$message->channel];
                call_user_func($callback, $message->payload, $this);
            } elseif (isset($this->defaultCallback)) {
                $callback = $this->defaultCallback;
                call_user_func($callback, $message, $this);
            }
        }
    }

    /**
     * Terminates the dispatcher loop.
     */
    public function stop()
    {
        $this->pubsub->stop();
    }

    /**
     * Return the prefix used for keys.
     *
     * @return string
     */
    protected function getPrefixKeys()
    {
        $options = $this->pubsub->getClient()->getOptions();

        if (isset($options->prefix)) {
            return $options->prefix->getPrefix();
        }

        return '';
    }
}
                                                                                                                                                                                                                                                                                                                                                                     predis/src/PubSub/RelayConsumer.php                                                                 0000644                 00000005626 15233650113 0013332 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\PubSub;

use Predis\NotSupportedException;

/**
 * Relay PUB/SUB consumer.
 */
class RelayConsumer extends Consumer
{
    /**
     * Subscribes to the specified channels.
     *
     * @param string   ...$channel One or more channel names.
     * @param callable $callback   The message callback.
     */
    public function subscribe($channel) // @phpstan-ignore-line
    {
        $channels = func_get_args();
        $callback = array_pop($channels);

        $this->statusFlags |= self::STATUS_SUBSCRIBED;

        $command = $this->client->createCommand('subscribe', [
            $channels,
            function ($relay, $channel, $message) use ($callback) {
                $callback((object) [
                    'kind' => is_null($message) ? self::SUBSCRIBE : self::MESSAGE,
                    'channel' => $channel,
                    'payload' => $message,
                ], $relay);
            },
        ]);

        $this->client->getConnection()->executeCommand($command);

        $this->invalidate();
    }

    /**
     * Subscribes to the specified channels using a pattern.
     *
     * @param string   ...$pattern One or more channel name patterns.
     * @param callable $callback   The message callback.
     */
    public function psubscribe(...$pattern) // @phpstan-ignore-line
    {
        $patterns = func_get_args();
        $callback = array_pop($patterns);

        $this->statusFlags |= self::STATUS_PSUBSCRIBED;

        $command = $this->client->createCommand('psubscribe', [
            $patterns,
            function ($relay, $pattern, $channel, $message) use ($callback) {
                $callback((object) [
                    'kind' => is_null($message) ? self::PSUBSCRIBE : self::PMESSAGE,
                    'pattern' => $pattern,
                    'channel' => $channel,
                    'payload' => $message,
                ], $relay);
            },
        ]);

        $this->client->getConnection()->executeCommand($command);

        $this->invalidate();
    }

    /**
     * {@inheritDoc}
     */
    protected function genericSubscribeInit($subscribeAction)
    {
        if (isset($this->options[$subscribeAction])) {
            throw new NotSupportedException('Relay does not support Pub/Sub constructor options.');
        }
    }

    /**
     * {@inheritDoc}
     */
    public function ping($payload = null)
    {
        throw new NotSupportedException('Relay does not support PING in Pub/Sub.');
    }

    /**
     * {@inheritDoc}
     */
    public function stop($drop = false)
    {
        return false;
    }

    /**
     * {@inheritDoc}
     */
    public function __destruct()
    {
        // NOOP
    }
}
                                                                                                          predis/src/ClientConfiguration.php                                                                  0000644                 00000002176 15233650113 0013305 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis;

class ClientConfiguration
{
    /**
     * @var array{modules: array}|string[][]
     */
    private static $config = [
        'modules' => [
            ['name' => 'Json', 'commandPrefix' => 'JSON'],
            ['name' => 'BloomFilter', 'commandPrefix' => 'BF'],
            ['name' => 'CuckooFilter', 'commandPrefix' => 'CF'],
            ['name' => 'CountMinSketch', 'commandPrefix' => 'CMS'],
            ['name' => 'TDigest', 'commandPrefix' => 'TDIGEST'],
            ['name' => 'TopK', 'commandPrefix' => 'TOPK'],
            ['name' => 'Search', 'commandPrefix' => 'FT'],
            ['name' => 'TimeSeries', 'commandPrefix' => 'TS'],
        ],
    ];

    /**
     * Returns available modules with configuration.
     *
     * @return array|string[][]
     */
    public static function getModules(): array
    {
        return self::$config['modules'];
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Pipeline/RelayAtomic.php                                                                 0000644                 00000003564 15233650113 0013317 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Pipeline;

use Predis\Connection\ConnectionInterface;
use Predis\Response\Error;
use Predis\Response\ServerException;
use Relay\Exception as RelayException;
use SplQueue;

class RelayAtomic extends Atomic
{
    /**
     * {@inheritdoc}
     */
    protected function executePipeline(ConnectionInterface $connection, SplQueue $commands)
    {
        /** @var \Predis\Connection\RelayConnection $connection */
        $client = $connection->getClient();

        $throw = $this->client->getOptions()->exceptions;

        try {
            $transaction = $client->multi();

            foreach ($commands as $command) {
                $name = $command->getId();

                in_array($name, $connection->atypicalCommands)
                    ? $transaction->{$name}(...$command->getArguments())
                    : $transaction->rawCommand($name, ...$command->getArguments());
            }

            $responses = $transaction->exec();

            if (!is_array($responses)) {
                return $responses;
            }

            foreach ($responses as $key => $response) {
                if ($response instanceof RelayException) {
                    if ($throw) {
                        throw $response;
                    }

                    $responses[$key] = new Error($response->getMessage());
                }
            }

            return $responses;
        } catch (RelayException $ex) {
            if ($client->getMode() !== $client::ATOMIC) {
                $client->discard();
            }

            throw new ServerException($ex->getMessage(), $ex->getCode(), $ex);
        }
    }
}
                                                                                                                                            predis/src/Pipeline/RelayPipeline.php                                                               0000644                 00000004225 15233650113 0013643 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Pipeline;

use Predis\Connection\ConnectionInterface;
use Predis\Connection\RelayConnection;
use Predis\Response\Error;
use Predis\Response\ServerException;
use Relay\Exception as RelayException;
use SplQueue;

class RelayPipeline extends Pipeline
{
    /**
     * Implements the logic to flush the queued commands and read the responses
     * from the current connection.
     *
     * @param  RelayConnection $connection Current connection instance.
     * @param  SplQueue        $commands   Queued commands.
     * @return array
     */
    protected function executePipeline(ConnectionInterface $connection, SplQueue $commands)
    {
        /** @var \Predis\Connection\RelayConnection $connection */
        $client = $connection->getClient();

        $throw = $this->client->getOptions()->exceptions;

        try {
            $pipeline = $client->pipeline();

            foreach ($commands as $command) {
                $name = $command->getId();

                in_array($name, $connection->atypicalCommands)
                    ? $pipeline->{$name}(...$command->getArguments())
                    : $pipeline->rawCommand($name, ...$command->getArguments());
            }

            $responses = $pipeline->exec();

            if (!is_array($responses)) {
                return $responses;
            }

            foreach ($responses as $key => $response) {
                if ($response instanceof RelayException) {
                    if ($throw) {
                        throw $response;
                    }

                    $responses[$key] = new Error($response->getMessage());
                }
            }

            return $responses;
        } catch (RelayException $ex) {
            if ($client->getMode() !== $client::ATOMIC) {
                $client->discard();
            }

            throw new ServerException($ex->getMessage(), $ex->getCode(), $ex);
        }
    }
}
                                                                                                                                                                                                                                                                                                                                                                           predis/src/Pipeline/Pipeline.php                                                                    0000644                 00000014754 15233650113 0012656 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Pipeline;

use Exception;
use InvalidArgumentException;
use Predis\ClientContextInterface;
use Predis\ClientException;
use Predis\ClientInterface;
use Predis\Command\CommandInterface;
use Predis\Connection\ConnectionInterface;
use Predis\Connection\Replication\ReplicationInterface;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\ResponseInterface;
use Predis\Response\ServerException;
use SplQueue;

/**
 * Implementation of a command pipeline in which write and read operations of
 * Redis commands are pipelined to alleviate the effects of network round-trips.
 *
 * {@inheritdoc}
 */
class Pipeline implements ClientContextInterface
{
    protected $client;
    private $pipeline;

    private $responses = [];
    private $running = false;

    /**
     * @param ClientInterface $client Client instance used by the context.
     */
    public function __construct(ClientInterface $client)
    {
        $this->client = $client;
        $this->pipeline = new SplQueue();
    }

    /**
     * Queues a command into the pipeline buffer.
     *
     * @param string $method    Command ID.
     * @param array  $arguments Arguments for the command.
     *
     * @return $this
     */
    public function __call($method, $arguments)
    {
        $command = $this->client->createCommand($method, $arguments);
        $this->recordCommand($command);

        return $this;
    }

    /**
     * Queues a command instance into the pipeline buffer.
     *
     * @param CommandInterface $command Command to be queued in the buffer.
     */
    protected function recordCommand(CommandInterface $command)
    {
        $this->pipeline->enqueue($command);
    }

    /**
     * Queues a command instance into the pipeline buffer.
     *
     * @param CommandInterface $command Command instance to be queued in the buffer.
     *
     * @return $this
     */
    public function executeCommand(CommandInterface $command)
    {
        $this->recordCommand($command);

        return $this;
    }

    /**
     * Throws an exception on -ERR responses returned by Redis.
     *
     * @param ConnectionInterface    $connection Redis connection that returned the error.
     * @param ErrorResponseInterface $response   Instance of the error response.
     *
     * @throws ServerException
     */
    protected function exception(ConnectionInterface $connection, ErrorResponseInterface $response)
    {
        $connection->disconnect();
        $message = $response->getMessage();

        throw new ServerException($message);
    }

    /**
     * Returns the underlying connection to be used by the pipeline.
     *
     * @return ConnectionInterface
     */
    protected function getConnection()
    {
        $connection = $this->getClient()->getConnection();

        if ($connection instanceof ReplicationInterface) {
            $connection->switchToMaster();
        }

        return $connection;
    }

    /**
     * Implements the logic to flush the queued commands and read the responses
     * from the current connection.
     *
     * @param ConnectionInterface $connection Current connection instance.
     * @param SplQueue            $commands   Queued commands.
     *
     * @return array
     */
    protected function executePipeline(ConnectionInterface $connection, SplQueue $commands)
    {
        foreach ($commands as $command) {
            $connection->writeRequest($command);
        }

        $responses = [];
        $exceptions = $this->throwServerExceptions();

        while (!$commands->isEmpty()) {
            $command = $commands->dequeue();
            $response = $connection->readResponse($command);

            if (!$response instanceof ResponseInterface) {
                $responses[] = $command->parseResponse($response);
            } elseif ($response instanceof ErrorResponseInterface && $exceptions) {
                $this->exception($connection, $response);
            } else {
                $responses[] = $response;
            }
        }

        return $responses;
    }

    /**
     * Flushes the buffer holding all of the commands queued so far.
     *
     * @param bool $send Specifies if the commands in the buffer should be sent to Redis.
     *
     * @return $this
     */
    public function flushPipeline($send = true)
    {
        if ($send && !$this->pipeline->isEmpty()) {
            $responses = $this->executePipeline($this->getConnection(), $this->pipeline);
            $this->responses = array_merge($this->responses, $responses);
        } else {
            $this->pipeline = new SplQueue();
        }

        return $this;
    }

    /**
     * Marks the running status of the pipeline.
     *
     * @param bool $bool Sets the running status of the pipeline.
     *
     * @throws ClientException
     */
    private function setRunning($bool)
    {
        if ($bool && $this->running) {
            throw new ClientException('The current pipeline context is already being executed.');
        }

        $this->running = $bool;
    }

    /**
     * Handles the actual execution of the whole pipeline.
     *
     * @param mixed $callable Optional callback for execution.
     *
     * @return array
     * @throws Exception
     * @throws InvalidArgumentException
     */
    public function execute($callable = null)
    {
        if ($callable && !is_callable($callable)) {
            throw new InvalidArgumentException('The argument must be a callable object.');
        }

        $exception = null;
        $this->setRunning(true);

        try {
            if ($callable) {
                call_user_func($callable, $this);
            }

            $this->flushPipeline();
        } catch (Exception $exception) {
            // NOOP
        }

        $this->setRunning(false);

        if ($exception) {
            throw $exception;
        }

        return $this->responses;
    }

    /**
     * Returns if the pipeline should throw exceptions on server errors.
     *
     * @return bool
     */
    protected function throwServerExceptions()
    {
        return (bool) $this->client->getOptions()->exceptions;
    }

    /**
     * Returns the underlying client instance used by the pipeline object.
     *
     * @return ClientInterface
     */
    public function getClient()
    {
        return $this->client;
    }
}
                    predis/src/Pipeline/Atomic.php                                                                      0000644                 00000006515 15233650113 0012321 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Pipeline;

use Predis\ClientException;
use Predis\ClientInterface;
use Predis\Connection\ConnectionInterface;
use Predis\Connection\NodeConnectionInterface;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\ResponseInterface;
use Predis\Response\ServerException;
use SplQueue;

/**
 * Command pipeline wrapped into a MULTI / EXEC transaction.
 */
class Atomic extends Pipeline
{
    /**
     * {@inheritdoc}
     */
    public function __construct(ClientInterface $client)
    {
        if (!$client->getCommandFactory()->supports('multi', 'exec', 'discard')) {
            throw new ClientException(
                "'MULTI', 'EXEC' and 'DISCARD' are not supported by the current command factory."
            );
        }

        parent::__construct($client);
    }

    /**
     * {@inheritdoc}
     */
    protected function getConnection()
    {
        $connection = $this->getClient()->getConnection();

        if (!$connection instanceof NodeConnectionInterface) {
            $class = __CLASS__;

            throw new ClientException("The class '$class' does not support aggregate connections.");
        }

        return $connection;
    }

    /**
     * {@inheritdoc}
     */
    protected function executePipeline(ConnectionInterface $connection, SplQueue $commands)
    {
        $commandFactory = $this->getClient()->getCommandFactory();
        $connection->executeCommand($commandFactory->create('multi'));

        foreach ($commands as $command) {
            $connection->writeRequest($command);
        }

        foreach ($commands as $command) {
            $response = $connection->readResponse($command);

            if ($response instanceof ErrorResponseInterface) {
                $connection->executeCommand($commandFactory->create('discard'));
                throw new ServerException($response->getMessage());
            }
        }

        $executed = $connection->executeCommand($commandFactory->create('exec'));

        if (!isset($executed)) {
            throw new ClientException(
                'The underlying transaction has been aborted by the server.'
            );
        }

        if (count($executed) !== count($commands)) {
            $expected = count($commands);
            $received = count($executed);

            throw new ClientException(
                "Invalid number of responses [expected $expected, received $received]."
            );
        }

        $responses = [];
        $sizeOfPipe = count($commands);
        $exceptions = $this->throwServerExceptions();

        for ($i = 0; $i < $sizeOfPipe; ++$i) {
            $command = $commands->dequeue();
            $response = $executed[$i];

            if (!$response instanceof ResponseInterface) {
                $responses[] = $command->parseResponse($response);
            } elseif ($response instanceof ErrorResponseInterface && $exceptions) {
                $this->exception($connection, $response);
            } else {
                $responses[] = $response;
            }

            unset($executed[$i]);
        }

        return $responses;
    }
}
                                                                                                                                                                                   predis/src/Pipeline/ConnectionErrorProof.php                                                        0000644                 00000007244 15233650113 0015224 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Pipeline;

use Predis\CommunicationException;
use Predis\Connection\Cluster\ClusterInterface;
use Predis\Connection\ConnectionInterface;
use Predis\Connection\NodeConnectionInterface;
use Predis\NotSupportedException;
use SplQueue;

/**
 * Command pipeline that does not throw exceptions on connection errors, but
 * returns the exception instances as the rest of the response elements.
 */
class ConnectionErrorProof extends Pipeline
{
    /**
     * {@inheritdoc}
     */
    protected function getConnection()
    {
        return $this->getClient()->getConnection();
    }

    /**
     * {@inheritdoc}
     */
    protected function executePipeline(ConnectionInterface $connection, SplQueue $commands)
    {
        if ($connection instanceof NodeConnectionInterface) {
            return $this->executeSingleNode($connection, $commands);
        } elseif ($connection instanceof ClusterInterface) {
            return $this->executeCluster($connection, $commands);
        } else {
            $class = get_class($connection);

            throw new NotSupportedException("The connection class '$class' is not supported.");
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function executeSingleNode(NodeConnectionInterface $connection, SplQueue $commands)
    {
        $responses = [];
        $sizeOfPipe = count($commands);

        foreach ($commands as $command) {
            try {
                $connection->writeRequest($command);
            } catch (CommunicationException $exception) {
                return array_fill(0, $sizeOfPipe, $exception);
            }
        }

        for ($i = 0; $i < $sizeOfPipe; ++$i) {
            $command = $commands->dequeue();

            try {
                $responses[$i] = $connection->readResponse($command);
            } catch (CommunicationException $exception) {
                $add = count($commands) - count($responses);
                $responses = array_merge($responses, array_fill(0, $add, $exception));

                break;
            }
        }

        return $responses;
    }

    /**
     * {@inheritdoc}
     */
    protected function executeCluster(ClusterInterface $connection, SplQueue $commands)
    {
        $responses = [];
        $sizeOfPipe = count($commands);
        $exceptions = [];

        foreach ($commands as $command) {
            $cmdConnection = $connection->getConnectionByCommand($command);

            if (isset($exceptions[spl_object_hash($cmdConnection)])) {
                continue;
            }

            try {
                $cmdConnection->writeRequest($command);
            } catch (CommunicationException $exception) {
                $exceptions[spl_object_hash($cmdConnection)] = $exception;
            }
        }

        for ($i = 0; $i < $sizeOfPipe; ++$i) {
            $command = $commands->dequeue();

            $cmdConnection = $connection->getConnectionByCommand($command);
            $connectionHash = spl_object_hash($cmdConnection);

            if (isset($exceptions[$connectionHash])) {
                $responses[$i] = $exceptions[$connectionHash];
                continue;
            }

            try {
                $responses[$i] = $cmdConnection->readResponse($command);
            } catch (CommunicationException $exception) {
                $responses[$i] = $exception;
                $exceptions[$connectionHash] = $exception;
            }
        }

        return $responses;
    }
}
                                                                                                                                                                                                                                                                                                                                                            predis/src/Pipeline/FireAndForget.php                                                               0000644                 00000001414 15233650113 0013555 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Pipeline;

use Predis\Connection\ConnectionInterface;
use SplQueue;

/**
 * Command pipeline that writes commands to the servers but discards responses.
 */
class FireAndForget extends Pipeline
{
    /**
     * {@inheritdoc}
     */
    protected function executePipeline(ConnectionInterface $connection, SplQueue $commands)
    {
        while (!$commands->isEmpty()) {
            $connection->writeRequest($commands->dequeue());
        }

        $connection->disconnect();

        return [];
    }
}
                                                                                                                                                                                                                                                    predis/src/Replication/ReplicationStrategy.php                                                      0000644                 00000020126 15233650113 0015577 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Replication;

use Predis\Command\CommandInterface;
use Predis\NotSupportedException;

/**
 * Defines a strategy for master/slave replication.
 */
class ReplicationStrategy
{
    protected $disallowed;
    protected $readonly;
    protected $readonlySHA1;
    protected $loadBalancing = true;

    public function __construct()
    {
        $this->disallowed = $this->getDisallowedOperations();
        $this->readonly = $this->getReadOnlyOperations();
        $this->readonlySHA1 = [];
    }

    /**
     * Returns if the specified command will perform a read-only operation
     * on Redis or not.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return bool
     * @throws NotSupportedException
     */
    public function isReadOperation(CommandInterface $command)
    {
        if (!$this->loadBalancing) {
            return false;
        }

        if (isset($this->disallowed[$id = $command->getId()])) {
            throw new NotSupportedException(
                "The command '$id' is not allowed in replication mode."
            );
        }

        if (isset($this->readonly[$id])) {
            if (true === $readonly = $this->readonly[$id]) {
                return true;
            }

            return call_user_func($readonly, $command);
        }

        if (($eval = $id === 'EVAL') || $id === 'EVALSHA') {
            $argument = $command->getArgument(0);
            $sha1 = $eval ? sha1(strval($argument)) : $argument;

            if (isset($this->readonlySHA1[$sha1])) {
                if (true === $readonly = $this->readonlySHA1[$sha1]) {
                    return true;
                }

                return call_user_func($readonly, $command);
            }
        }

        return false;
    }

    /**
     * Returns if the specified command is not allowed for execution in a master
     * / slave replication context.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return bool
     */
    public function isDisallowedOperation(CommandInterface $command)
    {
        return isset($this->disallowed[$command->getId()]);
    }

    /**
     * Checks if BITFIELD performs a read-only operation by looking for certain
     * SET and INCRYBY modifiers in the arguments array of the command.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return bool
     */
    protected function isBitfieldReadOnly(CommandInterface $command)
    {
        $arguments = $command->getArguments();
        $argc = count($arguments);

        if ($argc >= 2) {
            for ($i = 1; $i < $argc; ++$i) {
                $argument = strtoupper($arguments[$i]);
                if ($argument === 'SET' || $argument === 'INCRBY') {
                    return false;
                }
            }
        }

        return true;
    }

    /**
     * Checks if a GEORADIUS command is a readable operation by parsing the
     * arguments array of the specified command instance.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return bool
     */
    protected function isGeoradiusReadOnly(CommandInterface $command)
    {
        $arguments = $command->getArguments();
        $argc = count($arguments);
        $startIndex = $command->getId() === 'GEORADIUS' ? 5 : 4;

        if ($argc > $startIndex) {
            for ($i = $startIndex; $i < $argc; ++$i) {
                $argument = strtoupper($arguments[$i]);
                if ($argument === 'STORE' || $argument === 'STOREDIST') {
                    return false;
                }
            }
        }

        return true;
    }

    /**
     * Marks a command as a read-only operation.
     *
     * When the behavior of a command can be decided only at runtime depending
     * on its arguments, a callable object can be provided to dynamically check
     * if the specified command performs a read or a write operation.
     *
     * @param string $commandID Command ID.
     * @param mixed  $readonly  A boolean value or a callable object.
     */
    public function setCommandReadOnly($commandID, $readonly = true)
    {
        $commandID = strtoupper($commandID);

        if ($readonly) {
            $this->readonly[$commandID] = $readonly;
        } else {
            unset($this->readonly[$commandID]);
        }
    }

    /**
     * Marks a Lua script for EVAL and EVALSHA as a read-only operation. When
     * the behaviour of a script can be decided only at runtime depending on
     * its arguments, a callable object can be provided to dynamically check
     * if the passed instance of EVAL or EVALSHA performs write operations or
     * not.
     *
     * @param string $script   Body of the Lua script.
     * @param mixed  $readonly A boolean value or a callable object.
     */
    public function setScriptReadOnly($script, $readonly = true)
    {
        $sha1 = sha1($script);

        if ($readonly) {
            $this->readonlySHA1[$sha1] = $readonly;
        } else {
            unset($this->readonlySHA1[$sha1]);
        }
    }

    /**
     * Returns the default list of disallowed commands.
     *
     * @return array
     */
    protected function getDisallowedOperations()
    {
        return [
            'SHUTDOWN' => true,
            'INFO' => true,
            'DBSIZE' => true,
            'LASTSAVE' => true,
            'CONFIG' => true,
            'MONITOR' => true,
            'SLAVEOF' => true,
            'SAVE' => true,
            'BGSAVE' => true,
            'BGREWRITEAOF' => true,
            'SLOWLOG' => true,
        ];
    }

    /**
     * Returns the default list of commands performing read-only operations.
     *
     * @return array
     */
    protected function getReadOnlyOperations()
    {
        return [
            'EXISTS' => true,
            'TYPE' => true,
            'KEYS' => true,
            'SCAN' => true,
            'RANDOMKEY' => true,
            'TTL' => true,
            'GET' => true,
            'MGET' => true,
            'SUBSTR' => true,
            'STRLEN' => true,
            'GETRANGE' => true,
            'GETBIT' => true,
            'LLEN' => true,
            'LRANGE' => true,
            'LINDEX' => true,
            'SCARD' => true,
            'SISMEMBER' => true,
            'SINTER' => true,
            'SUNION' => true,
            'SDIFF' => true,
            'SMEMBERS' => true,
            'SSCAN' => true,
            'SRANDMEMBER' => true,
            'ZRANGE' => true,
            'ZREVRANGE' => true,
            'ZRANGEBYSCORE' => true,
            'ZREVRANGEBYSCORE' => true,
            'ZCARD' => true,
            'ZSCORE' => true,
            'ZCOUNT' => true,
            'ZRANK' => true,
            'ZREVRANK' => true,
            'ZSCAN' => true,
            'ZLEXCOUNT' => true,
            'ZRANGEBYLEX' => true,
            'ZREVRANGEBYLEX' => true,
            'HGET' => true,
            'HMGET' => true,
            'HEXISTS' => true,
            'HLEN' => true,
            'HKEYS' => true,
            'HVALS' => true,
            'HGETALL' => true,
            'HSCAN' => true,
            'HSTRLEN' => true,
            'PING' => true,
            'AUTH' => true,
            'SELECT' => true,
            'ECHO' => true,
            'QUIT' => true,
            'OBJECT' => true,
            'BITCOUNT' => true,
            'BITPOS' => true,
            'TIME' => true,
            'PFCOUNT' => true,
            'BITFIELD' => [$this, 'isBitfieldReadOnly'],
            'GEOHASH' => true,
            'GEOPOS' => true,
            'GEODIST' => true,
            'GEORADIUS' => [$this, 'isGeoradiusReadOnly'],
            'GEORADIUSBYMEMBER' => [$this, 'isGeoradiusReadOnly'],
        ];
    }

    /**
     * Disables reads to slaves when using
     * a replication topology.
     *
     * @return self
     */
    public function disableLoadBalancing(): self
    {
        $this->loadBalancing = false;

        return $this;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                          predis/src/Replication/RoleException.php                                                            0000644                 00000000754 15233650113 0014370 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Replication;

use Predis\CommunicationException;

/**
 * Exception class that identifies a role mismatch when connecting to node
 * managed by redis-sentinel.
 */
class RoleException extends CommunicationException
{
}
                    predis/src/Replication/MissingMasterException.php                                                   0000644                 00000000720 15233650113 0016245 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Replication;

use Predis\ClientException;

/**
 * Exception class that identifies when master is missing in a replication setup.
 */
class MissingMasterException extends ClientException
{
}
                                                predis/src/Command/Processor/ProcessorChain.php                                                     0000644                 00000006151 15233650113 0015613 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Processor;

use ArrayAccess;
use ArrayIterator;
use InvalidArgumentException;
use Predis\Command\CommandInterface;
use ReturnTypeWillChange;
use Traversable;

/**
 * Default implementation of a command processors chain.
 */
class ProcessorChain implements ArrayAccess, ProcessorInterface
{
    private $processors = [];

    /**
     * @param array $processors List of instances of ProcessorInterface.
     */
    public function __construct($processors = [])
    {
        foreach ($processors as $processor) {
            $this->add($processor);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function add(ProcessorInterface $processor)
    {
        $this->processors[] = $processor;
    }

    /**
     * {@inheritdoc}
     */
    public function remove(ProcessorInterface $processor)
    {
        if (false !== $index = array_search($processor, $this->processors, true)) {
            unset($this[$index]);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function process(CommandInterface $command)
    {
        for ($i = 0; $i < $count = count($this->processors); ++$i) {
            $this->processors[$i]->process($command);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function getProcessors()
    {
        return $this->processors;
    }

    /**
     * Returns an iterator over the list of command processor in the chain.
     *
     * @return Traversable<int, ProcessorInterface>
     */
    public function getIterator()
    {
        return new ArrayIterator($this->processors);
    }

    /**
     * Returns the number of command processors in the chain.
     *
     * @return int
     */
    public function count()
    {
        return count($this->processors);
    }

    /**
     * @param  int  $index
     * @return bool
     */
    #[ReturnTypeWillChange]
    public function offsetExists($index)
    {
        return isset($this->processors[$index]);
    }

    /**
     * @param  int                $index
     * @return ProcessorInterface
     */
    #[ReturnTypeWillChange]
    public function offsetGet($index)
    {
        return $this->processors[$index];
    }

    /**
     * @param  int                $index
     * @param  ProcessorInterface $processor
     * @return void
     */
    #[ReturnTypeWillChange]
    public function offsetSet($index, $processor)
    {
        if (!$processor instanceof ProcessorInterface) {
            throw new InvalidArgumentException(
                'Processor chain accepts only instances of `Predis\Command\Processor\ProcessorInterface`'
            );
        }

        $this->processors[$index] = $processor;
    }

    /**
     * @param  int  $index
     * @return void
     */
    #[ReturnTypeWillChange]
    public function offsetUnset($index)
    {
        unset($this->processors[$index]);
        $this->processors = array_values($this->processors);
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                       predis/src/Command/Processor/KeyPrefixProcessor.php                                                 0000644                 00000046451 15233650113 0016506 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Processor;

use InvalidArgumentException;
use Predis\Command\CommandInterface;
use Predis\Command\PrefixableCommandInterface;

/**
 * Command processor capable of prefixing keys stored in the arguments of Redis
 * commands supported.
 */
class KeyPrefixProcessor implements ProcessorInterface
{
    private $prefix;
    private $commands;

    /**
     * @param string $prefix Prefix for the keys.
     */
    public function __construct($prefix)
    {
        $this->prefix = $prefix;

        $prefixFirst = static::class . '::first';
        $prefixAll = static::class . '::all';
        $prefixInterleaved = static::class . '::interleaved';
        $prefixSkipFirst = static::class . '::skipFirst';
        $prefixSkipLast = static::class . '::skipLast';
        $prefixSort = static::class . '::sort';
        $prefixEvalKeys = static::class . '::evalKeys';
        $prefixZsetStore = static::class . '::zsetStore';
        $prefixMigrate = static::class . '::migrate';
        $prefixGeoradius = static::class . '::georadius';

        $this->commands = [
            /* ---------------- Redis 1.2 ---------------- */
            'EXISTS' => $prefixAll,
            'DEL' => $prefixAll,
            'TYPE' => $prefixFirst,
            'KEYS' => $prefixFirst,
            'RENAME' => $prefixAll,
            'RENAMENX' => $prefixAll,
            'EXPIRE' => $prefixFirst,
            'EXPIREAT' => $prefixFirst,
            'TTL' => $prefixFirst,
            'MOVE' => $prefixFirst,
            'SORT' => $prefixSort,
            'DUMP' => $prefixFirst,
            'RESTORE' => $prefixFirst,
            'SET' => $prefixFirst,
            'SETNX' => $prefixFirst,
            'MSET' => $prefixInterleaved,
            'MSETNX' => $prefixInterleaved,
            'GET' => $prefixFirst,
            'MGET' => $prefixAll,
            'GETSET' => $prefixFirst,
            'INCR' => $prefixFirst,
            'INCRBY' => $prefixFirst,
            'DECR' => $prefixFirst,
            'DECRBY' => $prefixFirst,
            'RPUSH' => $prefixFirst,
            'LPUSH' => $prefixFirst,
            'LLEN' => $prefixFirst,
            'LRANGE' => $prefixFirst,
            'LTRIM' => $prefixFirst,
            'LINDEX' => $prefixFirst,
            'LSET' => $prefixFirst,
            'LREM' => $prefixFirst,
            'LPOP' => $prefixFirst,
            'RPOP' => $prefixFirst,
            'RPOPLPUSH' => $prefixAll,
            'SADD' => $prefixFirst,
            'SREM' => $prefixFirst,
            'SPOP' => $prefixFirst,
            'SMOVE' => $prefixSkipLast,
            'SCARD' => $prefixFirst,
            'SISMEMBER' => $prefixFirst,
            'SINTER' => $prefixAll,
            'SINTERSTORE' => $prefixAll,
            'SUNION' => $prefixAll,
            'SUNIONSTORE' => $prefixAll,
            'SDIFF' => $prefixAll,
            'SDIFFSTORE' => $prefixAll,
            'SMEMBERS' => $prefixFirst,
            'SRANDMEMBER' => $prefixFirst,
            'ZADD' => $prefixFirst,
            'ZINCRBY' => $prefixFirst,
            'ZREM' => $prefixFirst,
            'ZRANGE' => $prefixFirst,
            'ZREVRANGE' => $prefixFirst,
            'ZRANGEBYSCORE' => $prefixFirst,
            'ZCARD' => $prefixFirst,
            'ZSCORE' => $prefixFirst,
            'ZREMRANGEBYSCORE' => $prefixFirst,
            /* ---------------- Redis 2.0 ---------------- */
            'SETEX' => $prefixFirst,
            'APPEND' => $prefixFirst,
            'SUBSTR' => $prefixFirst,
            'BLPOP' => $prefixSkipLast,
            'BRPOP' => $prefixSkipLast,
            'ZUNIONSTORE' => $prefixZsetStore,
            'ZINTERSTORE' => $prefixZsetStore,
            'ZCOUNT' => $prefixFirst,
            'ZRANK' => $prefixFirst,
            'ZREVRANK' => $prefixFirst,
            'ZREMRANGEBYRANK' => $prefixFirst,
            'HSET' => $prefixFirst,
            'HSETNX' => $prefixFirst,
            'HMSET' => $prefixFirst,
            'HINCRBY' => $prefixFirst,
            'HGET' => $prefixFirst,
            'HMGET' => $prefixFirst,
            'HDEL' => $prefixFirst,
            'HEXISTS' => $prefixFirst,
            'HLEN' => $prefixFirst,
            'HKEYS' => $prefixFirst,
            'HVALS' => $prefixFirst,
            'HGETALL' => $prefixFirst,
            'SUBSCRIBE' => $prefixAll,
            'UNSUBSCRIBE' => $prefixAll,
            'PSUBSCRIBE' => $prefixAll,
            'PUNSUBSCRIBE' => $prefixAll,
            'PUBLISH' => $prefixFirst,
            /* ---------------- Redis 2.2 ---------------- */
            'PERSIST' => $prefixFirst,
            'STRLEN' => $prefixFirst,
            'SETRANGE' => $prefixFirst,
            'GETRANGE' => $prefixFirst,
            'SETBIT' => $prefixFirst,
            'GETBIT' => $prefixFirst,
            'RPUSHX' => $prefixFirst,
            'LPUSHX' => $prefixFirst,
            'LINSERT' => $prefixFirst,
            'BRPOPLPUSH' => $prefixSkipLast,
            'ZREVRANGEBYSCORE' => $prefixFirst,
            'WATCH' => $prefixAll,
            /* ---------------- Redis 2.6 ---------------- */
            'PTTL' => $prefixFirst,
            'PEXPIRE' => $prefixFirst,
            'PEXPIREAT' => $prefixFirst,
            'PSETEX' => $prefixFirst,
            'INCRBYFLOAT' => $prefixFirst,
            'BITOP' => $prefixSkipFirst,
            'BITCOUNT' => $prefixFirst,
            'HINCRBYFLOAT' => $prefixFirst,
            'EVAL' => $prefixEvalKeys,
            'EVALSHA' => $prefixEvalKeys,
            'MIGRATE' => $prefixMigrate,
            /* ---------------- Redis 2.8 ---------------- */
            'SSCAN' => $prefixFirst,
            'ZSCAN' => $prefixFirst,
            'HSCAN' => $prefixFirst,
            'PFADD' => $prefixFirst,
            'PFCOUNT' => $prefixAll,
            'PFMERGE' => $prefixAll,
            'ZLEXCOUNT' => $prefixFirst,
            'ZRANGEBYLEX' => $prefixFirst,
            'ZREMRANGEBYLEX' => $prefixFirst,
            'ZREVRANGEBYLEX' => $prefixFirst,
            'BITPOS' => $prefixFirst,
            /* ---------------- Redis 3.2 ---------------- */
            'HSTRLEN' => $prefixFirst,
            'BITFIELD' => $prefixFirst,
            'GEOADD' => $prefixFirst,
            'GEOHASH' => $prefixFirst,
            'GEOPOS' => $prefixFirst,
            'GEODIST' => $prefixFirst,
            'GEORADIUS' => $prefixGeoradius,
            'GEORADIUSBYMEMBER' => $prefixGeoradius,
            /* ---------------- Redis 5.0 ---------------- */
            'XADD' => $prefixFirst,
            'XRANGE' => $prefixFirst,
            'XREVRANGE' => $prefixFirst,
            'XDEL' => $prefixFirst,
            'XLEN' => $prefixFirst,
            'XACK' => $prefixFirst,
            'XTRIM' => $prefixFirst,

            /* ---------------- Redis 6.2 ---------------- */
            'GETDEL' => $prefixFirst,

            /* ---------------- Redis 7.0 ---------------- */
            'EXPIRETIME' => $prefixFirst,

            /* RedisJSON */
            'JSON.ARRAPPEND' => $prefixFirst,
            'JSON.ARRINDEX' => $prefixFirst,
            'JSON.ARRINSERT' => $prefixFirst,
            'JSON.ARRLEN' => $prefixFirst,
            'JSON.ARRPOP' => $prefixFirst,
            'JSON.ARRTRIM' => $prefixFirst,
            'JSON.CLEAR' => $prefixFirst,
            'JSON.DEBUG MEMORY' => $prefixFirst,
            'JSON.DEL' => $prefixFirst,
            'JSON.FORGET' => $prefixFirst,
            'JSON.GET' => $prefixFirst,
            'JSON.MGET' => $prefixAll,
            'JSON.NUMINCRBY' => $prefixFirst,
            'JSON.OBJKEYS' => $prefixFirst,
            'JSON.OBJLEN' => $prefixFirst,
            'JSON.RESP' => $prefixFirst,
            'JSON.SET' => $prefixFirst,
            'JSON.STRAPPEND' => $prefixFirst,
            'JSON.STRLEN' => $prefixFirst,
            'JSON.TOGGLE' => $prefixFirst,
            'JSON.TYPE' => $prefixFirst,

            /* RedisBloom */
            'BF.ADD' => $prefixFirst,
            'BF.EXISTS' => $prefixFirst,
            'BF.INFO' => $prefixFirst,
            'BF.INSERT' => $prefixFirst,
            'BF.LOADCHUNK' => $prefixFirst,
            'BF.MADD' => $prefixFirst,
            'BF.MEXISTS' => $prefixFirst,
            'BF.RESERVE' => $prefixFirst,
            'BF.SCANDUMP' => $prefixFirst,
            'CF.ADD' => $prefixFirst,
            'CF.ADDNX' => $prefixFirst,
            'CF.COUNT' => $prefixFirst,
            'CF.DEL' => $prefixFirst,
            'CF.EXISTS' => $prefixFirst,
            'CF.INFO' => $prefixFirst,
            'CF.INSERT' => $prefixFirst,
            'CF.INSERTNX' => $prefixFirst,
            'CF.LOADCHUNK' => $prefixFirst,
            'CF.MEXISTS' => $prefixFirst,
            'CF.RESERVE' => $prefixFirst,
            'CF.SCANDUMP' => $prefixFirst,
            'CMS.INCRBY' => $prefixFirst,
            'CMS.INFO' => $prefixFirst,
            'CMS.INITBYDIM' => $prefixFirst,
            'CMS.INITBYPROB' => $prefixFirst,
            'CMS.QUERY' => $prefixFirst,
            'TDIGEST.ADD' => $prefixFirst,
            'TDIGEST.BYRANK' => $prefixFirst,
            'TDIGEST.BYREVRANK' => $prefixFirst,
            'TDIGEST.CDF' => $prefixFirst,
            'TDIGEST.CREATE' => $prefixFirst,
            'TDIGEST.INFO' => $prefixFirst,
            'TDIGEST.MAX' => $prefixFirst,
            'TDIGEST.MIN' => $prefixFirst,
            'TDIGEST.QUANTILE' => $prefixFirst,
            'TDIGEST.RANK' => $prefixFirst,
            'TDIGEST.RESET' => $prefixFirst,
            'TDIGEST.REVRANK' => $prefixFirst,
            'TDIGEST.TRIMMED_MEAN' => $prefixFirst,
            'TOPK.ADD' => $prefixFirst,
            'TOPK.INCRBY' => $prefixFirst,
            'TOPK.INFO' => $prefixFirst,
            'TOPK.LIST' => $prefixFirst,
            'TOPK.QUERY' => $prefixFirst,
            'TOPK.RESERVE' => $prefixFirst,

            /* RediSearch */
            'FT.AGGREGATE' => $prefixFirst,
            'FT.ALTER' => $prefixFirst,
            'FT.CREATE' => $prefixFirst,
            'FT.CURSOR DEL' => $prefixFirst,
            'FT.CURSOR READ' => $prefixFirst,
            'FT.DROPINDEX' => $prefixFirst,
            'FT.EXPLAIN' => $prefixFirst,
            'FT.INFO' => $prefixFirst,
            'FT.PROFILE' => $prefixFirst,
            'FT.SEARCH' => $prefixFirst,
            'FT.SPELLCHECK' => $prefixFirst,
            'FT.SYNDUMP' => $prefixFirst,
            'FT.SYNUPDATE' => $prefixFirst,
            'FT.TAGVALS' => $prefixFirst,

            /* Redis TimeSeries */
            'TS.ADD' => $prefixFirst,
            'TS.ALTER' => $prefixFirst,
            'TS.CREATE' => $prefixFirst,
            'TS.DECRBY' => $prefixFirst,
            'TS.DEL' => $prefixFirst,
            'TS.GET' => $prefixFirst,
            'TS.INCRBY' => $prefixFirst,
            'TS.INFO' => $prefixFirst,
            'TS.MGET' => $prefixFirst,
            'TS.MRANGE' => $prefixFirst,
            'TS.MREVRANGE' => $prefixFirst,
            'TS.QUERYINDEX' => $prefixFirst,
            'TS.RANGE' => $prefixFirst,
            'TS.REVRANGE' => $prefixFirst,
        ];
    }

    /**
     * Sets a prefix that is applied to all the keys.
     *
     * @param string $prefix Prefix for the keys.
     */
    public function setPrefix($prefix)
    {
        $this->prefix = $prefix;
    }

    /**
     * Gets the current prefix.
     *
     * @return string
     */
    public function getPrefix()
    {
        return $this->prefix;
    }

    /**
     * {@inheritdoc}
     */
    public function process(CommandInterface $command)
    {
        if ($command instanceof PrefixableCommandInterface) {
            $command->prefixKeys($this->prefix);
        } elseif (isset($this->commands[$commandID = strtoupper($command->getId())])) {
            $this->commands[$commandID]($command, $this->prefix);
        }
    }

    /**
     * Sets an handler for the specified command ID.
     *
     * The callback signature must have 2 parameters of the following types:
     *
     *   - Predis\Command\CommandInterface (command instance)
     *   - String (prefix)
     *
     * When the callback argument is omitted or NULL, the previously
     * associated handler for the specified command ID is removed.
     *
     * @param string $commandID The ID of the command to be handled.
     * @param mixed  $callback  A valid callable object or NULL.
     *
     * @throws InvalidArgumentException
     */
    public function setCommandHandler($commandID, $callback = null)
    {
        $commandID = strtoupper($commandID);

        if (!isset($callback)) {
            unset($this->commands[$commandID]);

            return;
        }

        if (!is_callable($callback)) {
            throw new InvalidArgumentException(
                'Callback must be a valid callable object or NULL'
            );
        }

        $this->commands[$commandID] = $callback;
    }

    /**
     * {@inheritdoc}
     */
    public function __toString()
    {
        return $this->getPrefix();
    }

    /**
     * Applies the specified prefix only the first argument.
     *
     * @param CommandInterface $command Command instance.
     * @param string           $prefix  Prefix string.
     */
    public static function first(CommandInterface $command, $prefix)
    {
        if ($arguments = $command->getArguments()) {
            $arguments[0] = "$prefix{$arguments[0]}";
            $command->setRawArguments($arguments);
        }
    }

    /**
     * Applies the specified prefix to all the arguments.
     *
     * @param CommandInterface $command Command instance.
     * @param string           $prefix  Prefix string.
     */
    public static function all(CommandInterface $command, $prefix)
    {
        if ($arguments = $command->getArguments()) {
            foreach ($arguments as &$key) {
                $key = "$prefix$key";
            }

            $command->setRawArguments($arguments);
        }
    }

    /**
     * Applies the specified prefix only to even arguments in the list.
     *
     * @param CommandInterface $command Command instance.
     * @param string           $prefix  Prefix string.
     */
    public static function interleaved(CommandInterface $command, $prefix)
    {
        if ($arguments = $command->getArguments()) {
            $length = count($arguments);

            for ($i = 0; $i < $length; $i += 2) {
                $arguments[$i] = "$prefix{$arguments[$i]}";
            }

            $command->setRawArguments($arguments);
        }
    }

    /**
     * Applies the specified prefix to all the arguments but the first one.
     *
     * @param CommandInterface $command Command instance.
     * @param string           $prefix  Prefix string.
     */
    public static function skipFirst(CommandInterface $command, $prefix)
    {
        if ($arguments = $command->getArguments()) {
            $length = count($arguments);

            for ($i = 1; $i < $length; ++$i) {
                $arguments[$i] = "$prefix{$arguments[$i]}";
            }

            $command->setRawArguments($arguments);
        }
    }

    /**
     * Applies the specified prefix to all the arguments but the last one.
     *
     * @param CommandInterface $command Command instance.
     * @param string           $prefix  Prefix string.
     */
    public static function skipLast(CommandInterface $command, $prefix)
    {
        if ($arguments = $command->getArguments()) {
            $length = count($arguments);

            for ($i = 0; $i < $length - 1; ++$i) {
                $arguments[$i] = "$prefix{$arguments[$i]}";
            }

            $command->setRawArguments($arguments);
        }
    }

    /**
     * Applies the specified prefix to the keys of a SORT command.
     *
     * @param CommandInterface $command Command instance.
     * @param string           $prefix  Prefix string.
     */
    public static function sort(CommandInterface $command, $prefix)
    {
        if ($arguments = $command->getArguments()) {
            $arguments[0] = "$prefix{$arguments[0]}";

            if (($count = count($arguments)) > 1) {
                for ($i = 1; $i < $count; ++$i) {
                    switch (strtoupper($arguments[$i])) {
                        case 'BY':
                        case 'STORE':
                            $arguments[$i] = "$prefix{$arguments[++$i]}";
                            break;

                        case 'GET':
                            $value = $arguments[++$i];
                            if ($value !== '#') {
                                $arguments[$i] = "$prefix$value";
                            }
                            break;

                        case 'LIMIT':
                            $i += 2;
                            break;
                    }
                }
            }

            $command->setRawArguments($arguments);
        }
    }

    /**
     * Applies the specified prefix to the keys of an EVAL-based command.
     *
     * @param CommandInterface $command Command instance.
     * @param string           $prefix  Prefix string.
     */
    public static function evalKeys(CommandInterface $command, $prefix)
    {
        if ($arguments = $command->getArguments()) {
            for ($i = 2; $i < $arguments[1] + 2; ++$i) {
                $arguments[$i] = "$prefix{$arguments[$i]}";
            }

            $command->setRawArguments($arguments);
        }
    }

    /**
     * Applies the specified prefix to the keys of Z[INTERSECTION|UNION]STORE.
     *
     * @param CommandInterface $command Command instance.
     * @param string           $prefix  Prefix string.
     */
    public static function zsetStore(CommandInterface $command, $prefix)
    {
        if ($arguments = $command->getArguments()) {
            $arguments[0] = "$prefix{$arguments[0]}";
            $length = ((int) $arguments[1]) + 2;

            for ($i = 2; $i < $length; ++$i) {
                $arguments[$i] = "$prefix{$arguments[$i]}";
            }

            $command->setRawArguments($arguments);
        }
    }

    /**
     * Applies the specified prefix to the key of a MIGRATE command.
     *
     * @param CommandInterface $command Command instance.
     * @param string           $prefix  Prefix string.
     */
    public static function migrate(CommandInterface $command, $prefix)
    {
        if ($arguments = $command->getArguments()) {
            $arguments[2] = "$prefix{$arguments[2]}";
            $command->setRawArguments($arguments);
        }
    }

    /**
     * Applies the specified prefix to the key of a GEORADIUS command.
     *
     * @param CommandInterface $command Command instance.
     * @param string           $prefix  Prefix string.
     */
    public static function georadius(CommandInterface $command, $prefix)
    {
        if ($arguments = $command->getArguments()) {
            $arguments[0] = "$prefix{$arguments[0]}";
            $startIndex = $command->getId() === 'GEORADIUS' ? 5 : 4;

            if (($count = count($arguments)) > $startIndex) {
                for ($i = $startIndex; $i < $count; ++$i) {
                    switch (strtoupper($arguments[$i])) {
                        case 'STORE':
                        case 'STOREDIST':
                            $arguments[$i] = "$prefix{$arguments[++$i]}";
                            break;
                    }
                }
            }

            $command->setRawArguments($arguments);
        }
    }
}
                                                                                                                                                                                                                       predis/src/Command/Processor/ProcessorInterface.php                                                 0000644                 00000001167 15233650113 0016473 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Processor;

use Predis\Command\CommandInterface;

/**
 * A command processor processes Redis commands before they are sent to Redis.
 */
interface ProcessorInterface
{
    /**
     * Processes the given Redis command.
     *
     * @param CommandInterface $command Command instance.
     */
    public function process(CommandInterface $command);
}
                                                                                                                                                                                                                                                                                                                                                                                                         predis/src/Command/Redis/PSETEX.php                                                                 0000644                 00000001013 15233650113 0012760 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/psetex
 */
class PSETEX extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'PSETEX';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/HSETNX.php                                                                 0000644                 00000001013 15233650113 0012761 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/hsetnx
 */
class HSETNX extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'HSETNX';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/HSCAN.php                                                                  0000644                 00000003501 15233650113 0012610 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/hscan
 */
class HSCAN extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'HSCAN';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 3 && is_array($arguments[2])) {
            $options = $this->prepareOptions(array_pop($arguments));
            $arguments = array_merge($arguments, $options);
        }

        parent::setArguments($arguments);
    }

    /**
     * Returns a list of options and modifiers compatible with Redis.
     *
     * @param array $options List of options.
     *
     * @return array
     */
    protected function prepareOptions($options)
    {
        $options = array_change_key_case($options, CASE_UPPER);
        $normalized = [];

        if (!empty($options['MATCH'])) {
            $normalized[] = 'MATCH';
            $normalized[] = $options['MATCH'];
        }

        if (!empty($options['COUNT'])) {
            $normalized[] = 'COUNT';
            $normalized[] = $options['COUNT'];
        }

        return $normalized;
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        if (is_array($data)) {
            $fields = $data[1];
            $result = [];

            for ($i = 0; $i < count($fields); ++$i) {
                $result[$fields[$i]] = $fields[++$i];
            }

            $data[1] = $result;
        }

        return $data;
    }
}
                                                                                                                                                                                               predis/src/Command/Redis/PUNSUBSCRIBE.php                                                           0000644                 00000001350 15233650113 0013660 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/punsubscribe
 */
class PUNSUBSCRIBE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'PUNSUBSCRIBE';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeArguments($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/ZPOPMIN.php                                                                0000644                 00000001616 15233650113 0013115 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/zpopmin
 */
class ZPOPMIN extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZPOPMIN';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        $result = [];

        for ($i = 0; $i < count($data); ++$i) {
            if (is_array($data[$i])) {
                $result[$data[$i][0]] = $data[$i][1]; // Relay
            } else {
                $result[$data[$i]] = $data[++$i];
            }
        }

        return $result;
    }
}
                                                                                                                  predis/src/Command/Redis/LSET.php                                                                   0000644                 00000001005 15233650113 0012520 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/lset
 */
class LSET extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'LSET';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/UNSUBSCRIBE.php                                                            0000644                 00000001345 15233650113 0013544 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/unsubscribe
 */
class UNSUBSCRIBE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'UNSUBSCRIBE';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeArguments($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/SUBSTR.php                                                                 0000644                 00000001013 15233650113 0012772 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/substr
 */
class SUBSTR extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SUBSTR';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/EXPIREAT.php                                                               0000644                 00000001420 15233650113 0013173 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Expire\ExpireOptions;

/**
 * @see http://redis.io/commands/expireat
 *
 * EXPIREAT has the same effect and semantic as EXPIRE, but instead of specifying
 * the number of seconds representing the TTL (time to live), it takes an absolute Unix timestamp
 */
class EXPIREAT extends RedisCommand
{
    use ExpireOptions;

    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'EXPIREAT';
    }
}
                                                                                                                                                                                                                                                predis/src/Command/Redis/LPOP.php                                                                   0000644                 00000001005 15233650113 0012523 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/lpop
 */
class LPOP extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'LPOP';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/SADD.php                                                                   0000644                 00000001317 15233650113 0012472 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/sadd
 */
class SADD extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SADD';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeVariadic($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                                 predis/src/Command/Redis/Search/FTDICTDEL.php                                                       0000644                 00000001040 15233650113 0014457 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.dictdel/
 *
 * Delete terms from a dictionary.
 */
class FTDICTDEL extends RedisCommand
{
    public function getId()
    {
        return 'FT.DICTDEL';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                predis/src/Command/Redis/Search/FTSPELLCHECK.php                                                    0000644                 00000001456 15233650113 0015037 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

class FTSPELLCHECK extends RedisCommand
{
    public function getId()
    {
        return 'FT.SPELLCHECK';
    }

    public function setArguments(array $arguments)
    {
        [$index, $query] = $arguments;
        $commandArguments = [];

        if (!empty($arguments[2])) {
            $commandArguments = $arguments[2]->toArray();
        }

        parent::setArguments(array_merge(
            [$index, $query],
            $commandArguments
        ));
    }
}
                                                                                                                                                                                                                  predis/src/Command/Redis/Search/FTALTER.php                                                         0000644                 00000002033 15233650113 0014261 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Argument\Search\SchemaFields\FieldInterface;
use Predis\Command\Command as RedisCommand;

class FTALTER extends RedisCommand
{
    public function getId()
    {
        return 'FT.ALTER';
    }

    public function setArguments(array $arguments)
    {
        [$index, $schema] = $arguments;
        $commandArguments = (!empty($arguments[2])) ? $arguments[2]->toArray() : [];

        $schema = array_reduce($schema, static function (array $carry, FieldInterface $field) {
            return array_merge($carry, $field->toArray());
        }, []);

        array_unshift($schema, 'SCHEMA', 'ADD');

        parent::setArguments(array_merge(
            [$index],
            $commandArguments,
            $schema
        ));
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/Search/FTCONFIG.php                                                        0000644                 00000001252 15233650113 0014361 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.config-get/
 * @see https://redis.io/commands/ft.config-set/
 *
 * Container command corresponds to any FT.CONFIG *.
 * Represents any FUNCTION command with subcommand as first argument.
 */
class FTCONFIG extends RedisCommand
{
    public function getId()
    {
        return 'FT.CONFIG';
    }
}
                                                                                                                                                                                                                                                                                                                                                      predis/src/Command/Redis/Search/FTCURSOR.php                                                        0000644                 00000001421 15233650113 0014427 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

class FTCURSOR extends RedisCommand
{
    public function getId()
    {
        return 'FT.CURSOR';
    }

    public function setArguments(array $arguments)
    {
        [$subcommand, $index, $cursorId] = $arguments;
        $commandArguments = (!empty($arguments[3])) ? $arguments[3]->toArray() : [];

        parent::setArguments(array_merge(
            [$subcommand, $index, $cursorId],
            $commandArguments
        ));
    }
}
                                                                                                                                                                                                                                               predis/src/Command/Redis/Search/FTSEARCH.php                                                        0000644                 00000001573 15233650113 0014367 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see  https://redis.io/commands/ft.search/
 *
 * Search the index with a textual query, returning either documents or just ids
 */
class FTSEARCH extends RedisCommand
{
    public function getId()
    {
        return 'FT.SEARCH';
    }

    public function setArguments(array $arguments)
    {
        [$index, $query] = $arguments;
        $commandArguments = (!empty($arguments[2])) ? $arguments[2]->toArray() : [];

        parent::setArguments(array_merge(
            [$index, $query],
            $commandArguments
        ));
    }
}
                                                                                                                                     predis/src/Command/Redis/Search/FTINFO.php                                                          0000644                 00000001047 15233650113 0014151 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.info/
 *
 * Return information and statistics on the index.
 */
class FTINFO extends RedisCommand
{
    public function getId()
    {
        return 'FT.INFO';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         predis/src/Command/Redis/Search/FTEXPLAIN.php                                                       0000644                 00000001623 15233650113 0014516 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.explain/
 *
 * Return the execution plan for a complex query.
 */
class FTEXPLAIN extends RedisCommand
{
    public function getId()
    {
        return 'FT.EXPLAIN';
    }

    public function setArguments(array $arguments)
    {
        [$index, $query] = $arguments;
        $commandArguments = [];

        if (!empty($arguments[2])) {
            $commandArguments = $arguments[2]->toArray();
        }

        parent::setArguments(array_merge(
            [$index, $query],
            $commandArguments
        ));
    }
}
                                                                                                             predis/src/Command/Redis/Search/FTDICTDUMP.php                                                      0000644                 00000001053 15233650113 0014624 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.dictdump/
 *
 * Dump all terms in the given dictionary.
 */
class FTDICTDUMP extends RedisCommand
{
    public function getId()
    {
        return 'FT.DICTDUMP';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/Search/FTDICTADD.php                                                       0000644                 00000001033 15233650113 0014445 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.dictadd/
 *
 * Add terms to a dictionary.
 */
class FTDICTADD extends RedisCommand
{
    public function getId()
    {
        return 'FT.DICTADD';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/Search/FTALIASADD.php                                                      0000644                 00000001035 15233650113 0014555 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.aliasadd/
 *
 * Add an alias to an index.
 */
class FTALIASADD extends RedisCommand
{
    public function getId()
    {
        return 'FT.ALIASADD';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   predis/src/Command/Redis/Search/FTSUGLEN.php                                                        0000644                 00000001065 15233650113 0014413 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.suglen/
 *
 * Get the size of an auto-complete suggestion dictionary.
 */
class FTSUGLEN extends RedisCommand
{
    public function getId()
    {
        return 'FT.SUGLEN';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/Search/FTAGGREGATE.php                                                     0000644                 00000001663 15233650113 0014710 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.aggregate/
 *
 * Run a search query on an index, and perform aggregate transformations
 * on the results, extracting statistics etc. from them
 */
class FTAGGREGATE extends RedisCommand
{
    public function getId()
    {
        return 'FT.AGGREGATE';
    }

    public function setArguments(array $arguments)
    {
        [$index, $query] = $arguments;
        $commandArguments = (!empty($arguments[2])) ? $arguments[2]->toArray() : [];

        parent::setArguments(array_merge(
            [$index, $query],
            $commandArguments
        ));
    }
}
                                                                             predis/src/Command/Redis/Search/FTALIASUPDATE.php                                                   0000644                 00000001246 15233650113 0015153 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.aliasupdate/
 *
 * Add an alias to an index. If the alias is already associated with another index,
 * FT.ALIASUPDATE removes the alias association with the previous index.
 */
class FTALIASUPDATE extends RedisCommand
{
    public function getId()
    {
        return 'FT.ALIASUPDATE';
    }
}
                                                                                                                                                                                                                                                                                                                                                          predis/src/Command/Redis/Search/FTALIASDEL.php                                                      0000644                 00000001042 15233650113 0014567 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.aliasdel/
 *
 * Remove an alias from an index.
 */
class FTALIASDEL extends RedisCommand
{
    public function getId()
    {
        return 'FT.ALIASDEL';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              predis/src/Command/Redis/Search/FTSYNUPDATE.php                                                     0000644                 00000001725 15233650113 0014775 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.synupdate/
 *
 * Update a synonym group
 */
class FTSYNUPDATE extends RedisCommand
{
    public function getId()
    {
        return 'FT.SYNUPDATE';
    }

    public function setArguments(array $arguments)
    {
        [$index, $synonymGroupId] = $arguments;
        $commandArguments = [];

        if (!empty($arguments[2])) {
            $commandArguments = $arguments[2]->toArray();
        }

        $terms = array_slice($arguments, 3);

        parent::setArguments(array_merge(
            [$index, $synonymGroupId],
            $commandArguments,
            $terms
        ));
    }
}
                                           predis/src/Command/Redis/Search/FTCREATE.php                                                        0000644                 00000002176 15233650113 0014365 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Argument\Search\SchemaFields\FieldInterface;
use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.create/
 *
 * Create an index with the given specification
 */
class FTCREATE extends RedisCommand
{
    public function getId()
    {
        return 'FT.CREATE';
    }

    public function setArguments(array $arguments)
    {
        [$index, $schema] = $arguments;
        $commandArguments = (!empty($arguments[2])) ? $arguments[2]->toArray() : [];

        $schema = array_reduce($schema, static function (array $carry, FieldInterface $field) {
            return array_merge($carry, $field->toArray());
        }, []);

        array_unshift($schema, 'SCHEMA');

        parent::setArguments(array_merge(
            [$index],
            $commandArguments,
            $schema
        ));
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/Search/FTSYNDUMP.php                                                       0000644                 00000001046 15233650113 0014554 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.syndump/
 *
 * Dump the contents of a synonym group.
 */
class FTSYNDUMP extends RedisCommand
{
    public function getId()
    {
        return 'FT.SYNDUMP';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          predis/src/Command/Redis/Search/FTPROFILE.php                                                       0000644                 00000001454 15233650113 0014520 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.profile/
 *
 * Perform a FT.SEARCH or FT.AGGREGATE command and collects performance information.
 */
class FTPROFILE extends RedisCommand
{
    public function getId()
    {
        return 'FT.PROFILE';
    }

    public function setArguments(array $arguments)
    {
        [$index, $arguments] = $arguments;

        parent::setArguments(array_merge(
            [$index],
            $arguments->toArray()
        ));
    }
}
                                                                                                                                                                                                                    predis/src/Command/Redis/Search/FTTAGVALS.php                                                       0000644                 00000001070 15233650113 0014513 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.tagvals/
 *
 * Return a distinct set of values indexed in a Tag field.
 */
class FTTAGVALS extends RedisCommand
{
    public function getId()
    {
        return 'FT.TAGVALS';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/Search/FTDROPINDEX.php                                                     0000644                 00000001434 15233650113 0014752 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

class FTDROPINDEX extends RedisCommand
{
    public function getId()
    {
        return 'FT.DROPINDEX';
    }

    public function setArguments(array $arguments)
    {
        [$index] = $arguments;
        $commandArguments = [];

        if (!empty($arguments[1])) {
            $commandArguments = $arguments[1]->toArray();
        }

        parent::setArguments(array_merge(
            [$index],
            $commandArguments
        ));
    }
}
                                                                                                                                                                                                                                    predis/src/Command/Redis/Search/FTSUGDEL.php                                                        0000644                 00000001046 15233650113 0014400 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.sugdel/
 *
 * Delete a string from a suggestion index.
 */
class FTSUGDEL extends RedisCommand
{
    public function getId()
    {
        return 'FT.SUGDEL';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          predis/src/Command/Redis/Search/FTSUGADD.php                                                        0000644                 00000001575 15233650113 0014373 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.sugadd/
 *
 * Add a suggestion string to an auto-complete suggestion dictionary.
 */
class FTSUGADD extends RedisCommand
{
    public function getId()
    {
        return 'FT.SUGADD';
    }

    public function setArguments(array $arguments)
    {
        [$key, $string, $score] = $arguments;
        $commandArguments = (!empty($arguments[3])) ? $arguments[3]->toArray() : [];

        parent::setArguments(array_merge(
            [$key, $string, $score],
            $commandArguments
        ));
    }
}
                                                                                                                                   predis/src/Command/Redis/Search/FTSUGGET.php                                                        0000644                 00000001523 15233650113 0014413 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Search;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ft.sugget/
 *
 * Get completion suggestions for a prefix.
 */
class FTSUGGET extends RedisCommand
{
    public function getId()
    {
        return 'FT.SUGGET';
    }

    public function setArguments(array $arguments)
    {
        [$key, $prefix] = $arguments;
        $commandArguments = (!empty($arguments[2])) ? $arguments[2]->toArray() : [];

        parent::setArguments(array_merge(
            [$key, $prefix],
            $commandArguments
        ));
    }
}
                                                                                                                                                                             predis/src/Command/Redis/HEXISTS.php                                                                0000644                 00000001016 15233650113 0013102 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/hexists
 */
class HEXISTS extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'HEXISTS';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/HGETALL.php                                                                0000644                 00000001534 15233650113 0013040 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/hgetall
 */
class HGETALL extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'HGETALL';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        if ($data !== array_values($data)) {
            return $data; // Relay
        }

        $result = [];

        for ($i = 0; $i < count($data); ++$i) {
            $result[$data[$i]] = $data[++$i];
        }

        return $result;
    }
}
                                                                                                                                                                    predis/src/Command/Redis/LCS.php                                                                    0000644                 00000003223 15233650113 0012376 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/lcs/
 *
 * The LCS command implements the longest common subsequence algorithm.
 */
class LCS extends RedisCommand
{
    public function getId()
    {
        return 'LCS';
    }

    public function setArguments(array $arguments)
    {
        if (isset($arguments[2]) && $arguments[2]) {
            $arguments[2] = 'LEN';
        }

        if (isset($arguments[3]) && $arguments[3]) {
            $arguments[3] = 'IDX';
        }

        if (isset($arguments[5]) && $arguments[5]) {
            $arguments[5] = 'WITHMATCHLEN';
        }

        if (isset($arguments[4])) {
            if ($arguments[4] !== 0) {
                $argumentsBefore = array_slice($arguments, 0, 4);
                $argumentsAfter = array_slice($arguments, 5);
                $arguments = array_merge($argumentsBefore, ['MINMATCHLEN', $arguments[4]], $argumentsAfter);
            } else {
                $arguments[4] = false;
            }
        }

        parent::setArguments($arguments);
        $this->filterArguments();
    }

    public function parseResponse($data)
    {
        if (is_array($data)) {
            if ($data !== array_values($data)) {
                return $data; // Relay
            }

            return [$data[0] => $data[1], $data[2] => $data[3]];
        }

        return $data;
    }
}
                                                                                                                                                                                                                                                                                                                                                                             predis/src/Command/Redis/LMOVE.php                                                                  0000644                 00000000664 15233650113 0012645 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

class LMOVE extends RedisCommand
{
    public function getId()
    {
        return 'LMOVE';
    }
}
                                                                            predis/src/Command/Redis/SUNIONSTORE.php                                                            0000644                 00000001474 15233650113 0013613 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/sunionstore
 */
class SUNIONSTORE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SUNIONSTORE';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 2 && is_array($arguments[1])) {
            $arguments = array_merge([$arguments[0]], $arguments[1]);
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                    predis/src/Command/Redis/DUMP.php                                                                   0000644                 00000001005 15233650113 0012516 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/dump
 */
class DUMP extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'DUMP';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/EVAL_RO.php                                                                0000644                 00000001271 15233650113 0013105 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Keys;

/**
 * @see https://redis.io/commands/eval_ro/
 *
 * This is a read-only variant of the EVAL command
 * that cannot execute commands that modify data.
 */
class EVAL_RO extends RedisCommand
{
    use Keys;

    protected static $keysArgumentPositionOffset = 1;

    public function getId()
    {
        return 'EVAL_RO';
    }
}
                                                                                                                                                                                                                                                                                                                                       predis/src/Command/Redis/ZSCORE.php                                                                 0000644                 00000001013 15233650113 0012755 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/zscore
 */
class ZSCORE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZSCORE';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/ZCOUNT.php                                                                 0000644                 00000001013 15233650113 0012772 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/zcount
 */
class ZCOUNT extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZCOUNT';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/HSET.php                                                                   0000644                 00000001005 15233650113 0012514 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/hset
 */
class HSET extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'HSET';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/RPOP.php                                                                   0000644                 00000001005 15233650113 0012531 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/rpop
 */
class RPOP extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'RPOP';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/FUNCTIONS.php                                                              0000644                 00000002322 15233650113 0013324 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Strategy\StrategyResolverInterface;
use Predis\Command\Strategy\SubcommandStrategyResolver;

/**
 * @see https://redis.io/commands/?name=function
 *
 * Container command corresponds to any FUNCTION *.
 * Represents any FUNCTION command with subcommand as first argument.
 */
class FUNCTIONS extends RedisCommand
{
    /**
     * @var StrategyResolverInterface
     */
    private $strategyResolver;

    public function __construct()
    {
        $this->strategyResolver = new SubcommandStrategyResolver();
    }

    public function getId()
    {
        return 'FUNCTION';
    }

    public function setArguments(array $arguments)
    {
        $strategy = $this->strategyResolver->resolve('functions', strtolower($arguments[0]));
        $arguments = $strategy->processArguments($arguments);

        parent::setArguments($arguments);
        $this->filterArguments();
    }
}
                                                                                                                                                                                                                                                                                                              predis/src/Command/Redis/GETSET.php                                                                 0000644                 00000001013 15233650113 0012743 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/getset
 */
class GETSET extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'GETSET';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/MONITOR.php                                                                0000644                 00000001016 15233650113 0013102 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/monitor
 */
class MONITOR extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'MONITOR';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/SINTER.php                                                                 0000644                 00000001326 15233650113 0012763 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/sinter
 */
class SINTER extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SINTER';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeArguments($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                          predis/src/Command/Redis/ZREVRANGEBYLEX.php                                                         0000644                 00000000765 15233650113 0014134 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

/**
 * @see http://redis.io/commands/zrevrangebylex
 */
class ZREVRANGEBYLEX extends ZRANGEBYLEX
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZREVRANGEBYLEX';
    }
}
           predis/src/Command/Redis/TYPE.php                                                                   0000644                 00000001772 15233650113 0012545 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/type
 */
class TYPE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'TYPE';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        if (is_string($data)) {
            return $data;
        }

        // Relay types
        switch ($data) {
            case 0: return 'none';
            case 1: return 'string';
            case 2: return 'set';
            case 3: return 'list';
            case 4: return 'zset';
            case 5: return 'hash';
            case 6: return 'stream';
            default: return $data;
        }
    }
}
      predis/src/Command/Redis/BITPOS.php                                                                 0000644                 00000001206 15233650113 0012754 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\BitByte;

/**
 * @see http://redis.io/commands/bitpos
 *
 * Return the position of the first bit set to 1 or 0 in a string.
 */
class BITPOS extends RedisCommand
{
    use BitByte;

    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'BITPOS';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                          predis/src/Command/Redis/LINDEX.php                                                                 0000644                 00000001013 15233650113 0012733 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/lindex
 */
class LINDEX extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'LINDEX';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/HRANDFIELD.php                                                             0000644                 00000002273 15233650113 0013361 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\With\WithValues;

/**
 * @see https://redis.io/commands/hrandfield/
 *
 * When called with just the key argument, return a random field from the hash value stored at key.
 *
 * If the provided count argument is positive, return an array of distinct fields.
 * The array's length is either count or the hash's number of fields (HLEN), whichever is lower.
 */
class HRANDFIELD extends RedisCommand
{
    use WithValues;

    public function getId()
    {
        return 'HRANDFIELD';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        if (!is_array($data)) {
            return $data;
        }

        // flatten Relay (RESP3) maps
        $return = [];

        array_walk_recursive($data, function ($value) use (&$return) {
            $return[] = $value;
        });

        return $return;
    }
}
                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/XRANGE.php                                                                 0000644                 00000002277 15233650113 0012751 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/xrange
 */
class XRANGE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'XRANGE';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 4) {
            $arguments[] = $arguments[3];
            $arguments[3] = 'COUNT';
        }

        parent::setArguments($arguments);
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        $result = [];
        foreach ($data as $entry) {
            $processed = [];
            $count = count($entry[1]);

            for ($i = 0; $i < $count; ++$i) {
                $processed[$entry[1][$i]] = $entry[1][++$i];
            }

            $result[$entry[0]] = $processed;
        }

        return $result;
    }
}
                                                                                                                                                                                                                                                                                                                                 predis/src/Command/Redis/WATCH.php                                                                  0000644                 00000001411 15233650113 0012620 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/watch
 */
class WATCH extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'WATCH';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (isset($arguments[0]) && is_array($arguments[0])) {
            $arguments = $arguments[0];
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                       predis/src/Command/Redis/LASTSAVE.php                                                               0000644                 00000001021 15233650113 0013171 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/lastsave
 */
class LASTSAVE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'LASTSAVE';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               predis/src/Command/Redis/ZADD.php                                                                   0000644                 00000001550 15233650113 0012500 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/zadd
 */
class ZADD extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZADD';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (is_array(end($arguments))) {
            foreach (array_pop($arguments) as $member => $score) {
                $arguments[] = $score;
                $arguments[] = $member;
            }
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                                                        predis/src/Command/Redis/SHUTDOWN.php                                                               0000644                 00000002534 15233650113 0013234 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/shutdown
 */
class SHUTDOWN extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SHUTDOWN';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (empty($arguments)) {
            parent::setArguments($arguments);

            return;
        }

        $processedArguments = [];

        if (array_key_exists(0, $arguments) && null !== $arguments[0]) {
            $processedArguments[] = ($arguments[0]) ? 'SAVE' : 'NOSAVE';
        }

        if (array_key_exists(1, $arguments) && false !== $arguments[1]) {
            $processedArguments[] = 'NOW';
        }

        if (array_key_exists(2, $arguments) && false !== $arguments[2]) {
            $processedArguments[] = 'FORCE';
        }

        if (array_key_exists(3, $arguments) && false !== $arguments[3]) {
            $processedArguments[] = 'ABORT';
        }

        parent::setArguments($processedArguments);
    }
}
                                                                                                                                                                    predis/src/Command/Redis/ZSCAN.php                                                                  0000644                 00000003515 15233650113 0012637 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/zscan
 */
class ZSCAN extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZSCAN';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 3 && is_array($arguments[2])) {
            $options = $this->prepareOptions(array_pop($arguments));
            $arguments = array_merge($arguments, $options);
        }

        parent::setArguments($arguments);
    }

    /**
     * Returns a list of options and modifiers compatible with Redis.
     *
     * @param array $options List of options.
     *
     * @return array
     */
    protected function prepareOptions($options)
    {
        $options = array_change_key_case($options, CASE_UPPER);
        $normalized = [];

        if (!empty($options['MATCH'])) {
            $normalized[] = 'MATCH';
            $normalized[] = $options['MATCH'];
        }

        if (!empty($options['COUNT'])) {
            $normalized[] = 'COUNT';
            $normalized[] = $options['COUNT'];
        }

        return $normalized;
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        if (is_array($data)) {
            $members = $data[1];
            $result = [];

            for ($i = 0; $i < count($members); ++$i) {
                $result[$members[$i]] = (float) $members[++$i];
            }

            $data[1] = $result;
        }

        return $data;
    }
}
                                                                                                                                                                                   predis/src/Command/Redis/SMISMEMBER.php                                                             0000644                 00000001074 15233650113 0013422 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/smismember/
 *
 * Returns whether each member is a member of the set stored at key.
 */
class SMISMEMBER extends RedisCommand
{
    public function getId()
    {
        return 'SMISMEMBER';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                    predis/src/Command/Redis/ZPOPMAX.php                                                                0000644                 00000001616 15233650113 0013117 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/zpopmax
 */
class ZPOPMAX extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZPOPMAX';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        $result = [];

        for ($i = 0; $i < count($data); ++$i) {
            if (is_array($data[$i])) {
                $result[$data[$i][0]] = $data[$i][1]; // Relay
            } else {
                $result[$data[$i]] = $data[++$i];
            }
        }

        return $result;
    }
}
                                                                                                                  predis/src/Command/Redis/LPUSHX.php                                                                 0000644                 00000001013 15233650113 0012773 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/lpushx
 */
class LPUSHX extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'LPUSHX';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/GETBIT.php                                                                 0000644                 00000001013 15233650113 0012726 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/getbit
 */
class GETBIT extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'GETBIT';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/BZMPOP.php                                                                 0000644                 00000001213 15233650113 0012761 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

/**
 * @see https://redis.io/commands/bzmpop/
 *
 * BZMPOP is the blocking variant of ZMPOP.
 */
class BZMPOP extends ZMPOP
{
    protected static $keysArgumentPositionOffset = 1;
    protected static $countArgumentPositionOffset = 3;
    protected static $modifierArgumentPositionOffset = 2;

    public function getId()
    {
        return 'BZMPOP';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/PING.php                                                                   0000644                 00000001005 15233650113 0012506 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/ping
 */
class PING extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'PING';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/ZRANDMEMBER.php                                                            0000644                 00000001533 15233650113 0013525 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\With\WithScores;

/**
 * @see https://redis.io/commands/zrandmember/
 *
 * Return a random element from the sorted set value stored at key.
 *
 * If the provided count argument is positive, return an array of distinct elements.
 *
 * If called with a negative count, the behavior changes and the command
 * is allowed to return the same element multiple times.
 */
class ZRANDMEMBER extends RedisCommand
{
    use WithScores;

    public function getId()
    {
        return 'ZRANDMEMBER';
    }
}
                                                                                                                                                                     predis/src/Command/Redis/COMMAND.php                                                                0000644                 00000001354 15233650113 0013036 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as BaseCommand;

/**
 * @see http://redis.io/commands/command
 */
class COMMAND extends BaseCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'COMMAND';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        // Relay (RESP3) uses maps and it might be good
        // to make the return value a breaking change

        return $data;
    }
}
                                                                                                                                                                                                                                                                                    predis/src/Command/Redis/BloomFilter/BFMADD.php                                                     0000644                 00000001312 15233650113 0015105 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\BloomFilter;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/bf.madd/
 *
 * Adds one or more items to the Bloom Filter and creates the filter if it does not exist yet.
 * This command operates identically to BF.ADD except that it allows multiple inputs and returns multiple values.
 */
class BFMADD extends RedisCommand
{
    public function getId()
    {
        return 'BF.MADD';
    }
}
                                                                                                                                                                                                                                                                                                                      predis/src/Command/Redis/BloomFilter/BFINSERT.php                                                   0000644                 00000003605 15233650113 0015413 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\BloomFilter;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\BloomFilters\Capacity;
use Predis\Command\Traits\BloomFilters\Error;
use Predis\Command\Traits\BloomFilters\Expansion;
use Predis\Command\Traits\BloomFilters\Items;
use Predis\Command\Traits\BloomFilters\NoCreate;

class BFINSERT extends RedisCommand
{
    use Capacity {
        Capacity::setArguments as setCapacity;
    }
    use Error {
        Error::setArguments as setErrorRate;
    }
    use Expansion {
        Expansion::setArguments as setExpansion;
    }
    use Items {
        Items::setArguments as setItems;
    }
    use NoCreate {
        NoCreate::setArguments as setNoCreate;
    }

    protected static $capacityArgumentPositionOffset = 1;
    protected static $errorArgumentPositionOffset = 2;
    protected static $expansionArgumentPositionOffset = 3;
    protected static $noCreateArgumentPositionOffset = 4;
    protected static $itemsArgumentPositionOffset = 6;

    public function getId()
    {
        return 'BF.INSERT';
    }

    public function setArguments(array $arguments)
    {
        $this->setNoCreate($arguments);
        $arguments = $this->getArguments();

        if (array_key_exists(5, $arguments) && $arguments[5]) {
            $arguments[5] = 'NONSCALING';
        }

        $this->setItems($arguments);
        $arguments = $this->getArguments();

        $this->setExpansion($arguments);
        $arguments = $this->getArguments();

        $this->setErrorRate($arguments);
        $arguments = $this->getArguments();

        $this->setCapacity($arguments);
        $this->filterArguments();
    }
}
                                                                                                                           predis/src/Command/Redis/BloomFilter/BFMEXISTS.php                                                  0000644                 00000001105 15233650113 0015534 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\BloomFilter;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/bf.mexists/
 *
 * Determines if one or more items may exist in the filter or not.
 */
class BFMEXISTS extends RedisCommand
{
    public function getId()
    {
        return 'BF.MEXISTS';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/BloomFilter/BFRESERVE.php                                                  0000644                 00000002405 15233650113 0015517 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\BloomFilter;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\BloomFilters\Expansion;

/**
 * @see https://redis.io/commands/bf.reserve/
 *
 * Creates an empty Bloom Filter with a single sub-filter for the initial capacity
 * requested and with an upper bound error_rate.
 *
 * By default, the filter auto-scales by creating additional sub-filters when capacity is reached.
 * The new sub-filter is created with size of the previous sub-filter multiplied by expansion.
 */
class BFRESERVE extends RedisCommand
{
    use Expansion {
        Expansion::setArguments as setExpansion;
    }

    protected static $expansionArgumentPositionOffset = 3;

    public function getId()
    {
        return 'BF.RESERVE';
    }

    public function setArguments(array $arguments)
    {
        if (array_key_exists(4, $arguments) && $arguments[4]) {
            $arguments[4] = 'NONSCALING';
        }

        $this->setExpansion($arguments);
        $this->filterArguments();
    }
}
                                                                                                                                                                                                                                                           predis/src/Command/Redis/BloomFilter/BFADD.php                                                      0000644                 00000001172 15233650113 0014774 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\BloomFilter;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/bf.add/
 *
 * Creates an empty Bloom Filter with a single sub-filter for the
 * initial capacity requested and with an upper bound error_rate.
 */
class BFADD extends RedisCommand
{
    public function getId()
    {
        return 'BF.ADD';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                      predis/src/Command/Redis/BloomFilter/BFLOADCHUNK.php                                                0000644                 00000001152 15233650113 0015712 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\BloomFilter;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/bf.loadchunk/
 *
 * Restores a filter previously saved using SCANDUMP. See the SCANDUMP command for example usage.
 */
class BFLOADCHUNK extends RedisCommand
{
    public function getId()
    {
        return 'BF.LOADCHUNK';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                      predis/src/Command/Redis/BloomFilter/BFINFO.php                                                     0000644                 00000003505 15233650113 0015141 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\BloomFilter;

use Predis\Command\Command as RedisCommand;
use UnexpectedValueException;

/**
 * @see https://redis.io/commands/bf.info/
 *
 * Return information about key filter.
 */
class BFINFO extends RedisCommand
{
    /**
     * @var string[]
     */
    private $modifierEnum = [
        'capacity' => 'CAPACITY',
        'size' => 'SIZE',
        'filters' => 'FILTERS',
        'items' => 'ITEMS',
        'expansion' => 'EXPANSION',
    ];

    public function getId()
    {
        return 'BF.INFO';
    }

    public function setArguments(array $arguments)
    {
        if (isset($arguments[1])) {
            $modifier = array_pop($arguments);

            if ($modifier === '') {
                parent::setArguments($arguments);

                return;
            }

            if (!in_array(strtoupper($modifier), $this->modifierEnum)) {
                $enumValues = implode(', ', array_keys($this->modifierEnum));
                throw new UnexpectedValueException("Argument accepts only: {$enumValues} values");
            }

            $arguments[] = $this->modifierEnum[strtolower($modifier)];
        }

        parent::setArguments($arguments);
    }

    public function parseResponse($data)
    {
        if (count($data) > 1) {
            $result = [];

            for ($i = 0, $iMax = count($data); $i < $iMax; ++$i) {
                if (array_key_exists($i + 1, $data)) {
                    $result[(string) $data[$i]] = $data[++$i];
                }
            }

            return $result;
        }

        return $data;
    }
}
                                                                                                                                                                                           predis/src/Command/Redis/BloomFilter/BFEXISTS.php                                                   0000644                 00000001103 15233650113 0015415 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\BloomFilter;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/bf.exists/
 *
 * Determines whether an item may exist in the Bloom Filter or not.
 */
class BFEXISTS extends RedisCommand
{
    public function getId()
    {
        return 'BF.EXISTS';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                             predis/src/Command/Redis/BloomFilter/BFSCANDUMP.php                                                 0000644                 00000001233 15233650113 0015614 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\BloomFilter;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/bf.scandump/
 *
 * Begins an incremental save of the bloom filter.
 * This is useful for large bloom filters which cannot fit into the normal DUMP and RESTORE model.
 */
class BFSCANDUMP extends RedisCommand
{
    public function getId()
    {
        return 'BF.SCANDUMP';
    }
}
                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/ZMPOP.php                                                                  0000644                 00000003643 15233650113 0012670 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Count;
use Predis\Command\Traits\Keys;
use Predis\Command\Traits\MinMaxModifier;

/**
 * @see https://redis.io/commands/zmpop/
 *
 * Pops one or more elements, that are member-score pairs,
 * from the first non-empty sorted set in the provided list of key names.
 */
class ZMPOP extends RedisCommand
{
    use Keys {
        Keys::setArguments as setKeys;
    }
    use Count {
        Count::setArguments as setCount;
    }
    use MinMaxModifier;

    protected static $keysArgumentPositionOffset = 0;
    protected static $countArgumentPositionOffset = 2;
    protected static $modifierArgumentPositionOffset = 1;

    public function getId()
    {
        return 'ZMPOP';
    }

    public function setArguments(array $arguments)
    {
        $this->setCount($arguments);
        $arguments = $this->getArguments();

        $this->resolveModifier(static::$modifierArgumentPositionOffset, $arguments);

        $this->setKeys($arguments);
        $arguments = $this->getArguments();

        parent::setArguments($arguments);
    }

    public function parseResponse($data)
    {
        $key = array_shift($data);

        if (null === $key) {
            return [$key];
        }

        $data = $data[0];
        $parsedData = [];

        for ($i = 0, $iMax = count($data); $i < $iMax; $i++) {
            for ($j = 0, $jMax = count($data[$i]); $j < $jMax; ++$j) {
                if ($data[$i][$j + 1] ?? false) {
                    $parsedData[$data[$i][$j]] = $data[$i][++$j];
                }
            }
        }

        return array_combine([$key], [$parsedData]);
    }
}
                                                                                             predis/src/Command/Redis/BZPOPMIN.php                                                               0000644                 00000001554 15233650113 0013220 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Redis\AbstractCommand\BZPOPBase;

/**
 * @see https://redis.io/commands/bzpopmin/
 *
 * BZPOPMIN is the blocking variant of the sorted set ZPOPMIN primitive.
 *
 * It is the blocking version because it blocks the connection when there are
 * no members to pop from any of the given sorted sets.
 * A member with the lowest score is popped from first sorted set that is non-empty,
 * with the given keys being checked in the order that they are given.
 */
class BZPOPMIN extends BZPOPBase
{
    public function getId(): string
    {
        return 'BZPOPMIN';
    }
}
                                                                                                                                                    predis/src/Command/Redis/ZMSCORE.php                                                                0000644                 00000001313 15233650113 0013075 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/zmscore/
 *
 * Returns the scores associated with the specified members
 * in the sorted set stored at key.
 *
 * For every member that does not exist in the sorted set, a null value is returned.
 */
class ZMSCORE extends RedisCommand
{
    /**
     * {@inheritDoc}
     */
    public function getId()
    {
        return 'ZMSCORE';
    }
}
                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/ZRANK.php                                                                  0000644                 00000001010 15233650113 0012632 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/zrank
 */
class ZRANK extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZRANK';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/BZPOPMAX.php                                                               0000644                 00000001555 15233650113 0013223 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Redis\AbstractCommand\BZPOPBase;

/**
 * @see https://redis.io/commands/bzpopmax/
 *
 * BZPOPMAX is the blocking variant of the sorted set ZPOPMAX primitive.
 *
 * It is the blocking version because it blocks the connection when there are
 * no members to pop from any of the given sorted sets.
 * A member with the highest score is popped from first sorted set that is non-empty,
 * with the given keys being checked in the order that they are given.
 */
class BZPOPMAX extends BZPOPBase
{
    public function getId(): string
    {
        return 'BZPOPMAX';
    }
}
                                                                                                                                                   predis/src/Command/Redis/INCRBYFLOAT.php                                                            0000644                 00000001032 15233650113 0013525 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/incrbyfloat
 */
class INCRBYFLOAT extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'INCRBYFLOAT';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      predis/src/Command/Redis/Container/Search/FTCONFIG.php                                              0000644                 00000001221 15233650113 0016277 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Container\Search;

use Predis\Command\Redis\Container\AbstractContainer;
use Predis\Response\Status;

/**
 * @method array  get(string $option)
 * @method array  help(string $option)
 * @method Status set(string $option, $value)
 */
class FTCONFIG extends AbstractContainer
{
    public function getContainerCommandId(): string
    {
        return 'FTCONFIG';
    }
}
                                                                                                                                                                                                                                                                                                                                                                               predis/src/Command/Redis/Container/Search/FTCURSOR.php                                              0000644                 00000001327 15233650113 0016356 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Container\Search;

use Predis\Command\Argument\Search\CursorArguments;
use Predis\Command\Redis\Container\AbstractContainer;
use Predis\Response\Status;

/**
 * @method Status del(string $index, int $cursorId)
 * @method array  read(string $index, int $cursorId, ?CursorArguments $arguments = null)
 */
class FTCURSOR extends AbstractContainer
{
    public function getContainerCommandId(): string
    {
        return 'FTCURSOR';
    }
}
                                                                                                                                                                                                                                                                                                         predis/src/Command/Redis/Container/ContainerInterface.php                                           0000644                 00000001436 15233650113 0017446 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Container;

interface ContainerInterface
{
    /**
     * Creates Redis container command with subcommand as virtual method name
     * and sends a request to the server.
     *
     * @param  string $subcommandID
     * @param  array  $arguments
     * @return mixed
     */
    public function __call(string $subcommandID, array $arguments);

    /**
     * Returns containerCommandId of specific container command.
     *
     * @return string
     */
    public function getContainerCommandId(): string;
}
                                                                                                                                                                                                                                  predis/src/Command/Redis/Container/FunctionContainer.php                                            0000644                 00000001543 15233650113 0017332 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Container;

use Predis\Response\Status;

/**
 * @method Status delete(string $libraryName)
 * @method string dump()
 * @method Status flush(?string $mode = null)
 * @method Status kill()
 * @method array  list(string $libraryNamePattern = null, bool $withCode = false)
 * @method string load(string $functionCode, bool $replace = 'false')
 * @method Status restore(string $value, string $policy = null)
 * @method array  stats()
 */
class FunctionContainer extends AbstractContainer
{
    public function getContainerCommandId(): string
    {
        return 'FUNCTIONS';
    }
}
                                                                                                                                                             predis/src/Command/Redis/Container/ACL.php                                                          0000644                 00000001204 15233650113 0014273 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Container;

use Predis\Response\Status;

/**
 * @method Status dryRun(string $username, string $command, ...$arguments)
 * @method array  getUser(string $username)
 * @method Status setUser(string $username, string ...$rules)
 */
class ACL extends AbstractContainer
{
    public function getContainerCommandId(): string
    {
        return 'acl';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                            predis/src/Command/Redis/Container/Json/JSONDEBUG.php                                               0000644                 00000001105 15233650113 0016125 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Container\Json;

use Predis\Command\Redis\Container\AbstractContainer;

/**
 * @method array memory(string $key, string $path)
 * @method array help()
 */
class JSONDEBUG extends AbstractContainer
{
    public function getContainerCommandId(): string
    {
        return 'JSONDEBUG';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/Container/AbstractContainer.php                                            0000644                 00000001667 15233650113 0017317 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Container;

use Predis\ClientInterface;

abstract class AbstractContainer implements ContainerInterface
{
    /**
     * @var ClientInterface
     */
    protected $client;

    public function __construct(ClientInterface $client)
    {
        $this->client = $client;
    }

    /**
     * {@inheritDoc}
     */
    public function __call(string $subcommandID, array $arguments)
    {
        array_unshift($arguments, strtoupper($subcommandID));

        return $this->client->executeCommand(
            $this->client->createCommand($this->getContainerCommandId(), $arguments)
        );
    }

    abstract public function getContainerCommandId(): string;
}
                                                                         predis/src/Command/Redis/Container/CLUSTER.php                                                      0000644                 00000001172 15233650113 0015021 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Container;

use Predis\Response\Status;

/**
 * @method Status addSlotsRange(int ...$startEndSlots)
 * @method Status delSlotsRange(int ...$startEndSlots)
 * @method array  links()
 * @method array  shards()
 */
class CLUSTER extends AbstractContainer
{
    public function getContainerCommandId(): string
    {
        return 'CLUSTER';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                      predis/src/Command/Redis/Container/ContainerFactory.php                                             0000644                 00000004541 15233650113 0017155 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Container;

use Predis\ClientConfiguration;
use Predis\ClientInterface;
use UnexpectedValueException;

class ContainerFactory
{
    private const CONTAINER_NAMESPACE = "Predis\Command\Redis\Container";

    /**
     * Mappings for class names that corresponds to PHP reserved words.
     *
     * @var array
     */
    private static $specialMappings = [
        'FUNCTION' => FunctionContainer::class,
    ];

    /**
     * Creates container command.
     *
     * @param  ClientInterface    $client
     * @param  string             $containerCommandID
     * @return ContainerInterface
     */
    public static function create(ClientInterface $client, string $containerCommandID): ContainerInterface
    {
        $containerCommandID = strtoupper($containerCommandID);
        $commandModule = self::resolveCommandModuleByPrefix($containerCommandID);

        if (null !== $commandModule) {
            if (class_exists($containerClass = self::CONTAINER_NAMESPACE . '\\' . $commandModule . '\\' . $containerCommandID)) {
                return new $containerClass($client);
            }

            throw new UnexpectedValueException('Given module container command is not supported.');
        }

        if (class_exists($containerClass = self::CONTAINER_NAMESPACE . '\\' . $containerCommandID)) {
            return new $containerClass($client);
        }

        if (array_key_exists($containerCommandID, self::$specialMappings)) {
            $containerClass = self::$specialMappings[$containerCommandID];

            return new $containerClass($client);
        }

        throw new UnexpectedValueException('Given container command is not supported.');
    }

    /**
     * @param  string      $commandID
     * @return string|null
     */
    private static function resolveCommandModuleByPrefix(string $commandID): ?string
    {
        $modules = ClientConfiguration::getModules();

        foreach ($modules as $module) {
            if (preg_match("/^{$module['commandPrefix']}/", $commandID)) {
                return $module['name'];
            }
        }

        return null;
    }
}
                                                                                                                                                               predis/src/Command/Redis/ZLEXCOUNT.php                                                              0000644                 00000001024 15233650113 0013345 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/zlexcount
 */
class ZLEXCOUNT extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZLEXCOUNT';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            predis/src/Command/Redis/FCALL_RO.php                                                               0000644                 00000001747 15233650113 0013207 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/fcall_ro/
 *
 * This is a read-only variant of the FCALL command that cannot execute commands that modify data.
 */
class FCALL_RO extends RedisCommand
{
    public function getId()
    {
        return 'FCALL_RO';
    }

    public function setArguments(array $arguments)
    {
        $processedArguments = array_merge([$arguments[0], count($arguments[1])], $arguments[1]);

        if (count($arguments) > 2) {
            for ($i = 2, $iMax = count($arguments); $i < $iMax; $i++) {
                $processedArguments[] = $arguments[$i];
            }
        }

        parent::setArguments($processedArguments);
    }
}
                         predis/src/Command/Redis/TTL.php                                                                    0000644                 00000001002 15233650113 0012411 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/ttl
 */
class TTL extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'TTL';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              predis/src/Command/Redis/ZREMRANGEBYLEX.php                                                         0000644                 00000001043 15233650113 0014111 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/zremrangebylex
 */
class ZREMRANGEBYLEX extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZREMRANGEBYLEX';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             predis/src/Command/Redis/MSET.php                                                                   0000644                 00000001722 15233650113 0012527 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/mset
 */
class MSET extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'MSET';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 1 && is_array($arguments[0])) {
            $flattenedKVs = [];
            $args = $arguments[0];

            foreach ($args as $k => $v) {
                $flattenedKVs[] = $k;
                $flattenedKVs[] = $v;
            }

            $arguments = $flattenedKVs;
        }

        parent::setArguments($arguments);
    }
}
                                              predis/src/Command/Redis/ZRANGEBYSCORE.php                                                          0000644                 00000002744 15233650113 0014001 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

/**
 * @see http://redis.io/commands/zrangebyscore
 */
class ZRANGEBYSCORE extends ZRANGE
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZRANGEBYSCORE';
    }

    /**
     * {@inheritdoc}
     */
    protected function prepareOptions($options)
    {
        $opts = array_change_key_case($options, CASE_UPPER);
        $finalizedOpts = [];

        if (isset($opts['LIMIT']) && is_array($opts['LIMIT'])) {
            $limit = array_change_key_case($opts['LIMIT'], CASE_UPPER);

            $finalizedOpts[] = 'LIMIT';
            $finalizedOpts[] = $limit['OFFSET'] ?? $limit[0];
            $finalizedOpts[] = $limit['COUNT'] ?? $limit[1];
        }

        return array_merge($finalizedOpts, parent::prepareOptions($options));
    }

    /**
     * {@inheritdoc}
     */
    protected function withScores()
    {
        $arguments = $this->getArguments();

        for ($i = 3; $i < count($arguments); ++$i) {
            switch (strtoupper($arguments[$i])) {
                case 'WITHSCORES':
                    return true;

                case 'LIMIT':
                    $i += 2;
                    break;
            }
        }

        return false;
    }
}
                            predis/src/Command/Redis/BITFIELD.php                                                               0000644                 00000001021 15233650113 0013131 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/bitfield
 */
class BITFIELD extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'BITFIELD';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               predis/src/Command/Redis/MOVE.php                                                                   0000644                 00000001005 15233650113 0012517 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/move
 */
class MOVE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'MOVE';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/GEOPOS.php                                                                 0000644                 00000001521 15233650113 0012750 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/geopos
 */
class GEOPOS extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'GEOPOS';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 2 && is_array($arguments[1])) {
            $members = array_pop($arguments);
            $arguments = array_merge($arguments, $members);
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                               predis/src/Command/Redis/ZDIFFSTORE.php                                                             0000644                 00000001661 15233650113 0013440 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Keys;

/**
 * @see https://redis.io/commands/zdiffstore/
 *
 * Computes the difference between the first and all successive input sorted sets
 * and stores the result in destination. The total number of input keys is specified by numkeys.
 *
 * Keys that do not exist are considered to be empty sets.
 *
 * If destination already exists, it is overwritten.
 */
class ZDIFFSTORE extends RedisCommand
{
    use Keys {
        Keys::setArguments as setKeys;
    }

    public static $keysArgumentPositionOffset = 1;

    public function getId()
    {
        return 'ZDIFFSTORE';
    }
}
                                                                               predis/src/Command/Redis/PUBLISH.php                                                                0000644                 00000001016 15233650113 0013061 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/publish
 */
class PUBLISH extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'PUBLISH';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/INCR.php                                                                   0000644                 00000001005 15233650113 0012504 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/incr
 */
class INCR extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'INCR';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/HLEN.php                                                                   0000644                 00000001005 15233650113 0012477 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/hlen
 */
class HLEN extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'HLEN';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/HVALS.php                                                                  0000644                 00000001010 15233650113 0012622 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/hvals
 */
class HVALS extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'HVALS';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/SREM.php                                                                   0000644                 00000001317 15233650113 0012525 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/srem
 */
class SREM extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SREM';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeVariadic($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                                 predis/src/Command/Redis/COPY.php                                                                   0000644                 00000001737 15233650113 0012537 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\DB;
use Predis\Command\Traits\Replace;

/**
 * @see https://redis.io/commands/copy/
 *
 * This command copies the value stored at the source key to the destination key.
 */
class COPY extends RedisCommand
{
    use DB {
        DB::setArguments as setDB;
    }
    use Replace {
        Replace::setArguments as setReplace;
    }

    protected static $dbArgumentPositionOffset = 2;

    public function getId()
    {
        return 'COPY';
    }

    public function setArguments(array $arguments)
    {
        $this->setDB($arguments);
        $arguments = $this->getArguments();

        $this->setReplace($arguments);
    }
}
                                 predis/src/Command/Redis/MSETNX.php                                                                 0000644                 00000000726 15233650113 0013000 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

/**
 * @see http://redis.io/commands/msetnx
 */
class MSETNX extends MSET
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'MSETNX';
    }
}
                                          predis/src/Command/Redis/ZCARD.php                                                                  0000644                 00000001010 15233650113 0012610 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/zcard
 */
class ZCARD extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZCARD';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/AbstractCommand/BZPOPBase.php                                              0000644                 00000001633 15233650113 0016507 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\AbstractCommand;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Keys;

abstract class BZPOPBase extends RedisCommand
{
    use Keys {
        Keys::setArguments as setKeys;
    }

    protected static $keysArgumentPositionOffset = 0;

    abstract public function getId(): string;

    public function setArguments(array $arguments)
    {
        $this->setKeys($arguments, false);
    }

    public function parseResponse($data)
    {
        $key = array_shift($data);

        if (null === $key) {
            return [$key];
        }

        return array_combine([$key], [[$data[0] => $data[1]]]);
    }
}
                                                                                                     predis/src/Command/Redis/LRANGE.php                                                                 0000644                 00000001013 15233650113 0012720 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/lrange
 */
class LRANGE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'LRANGE';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/HKEYS.php                                                                  0000644                 00000001010 15233650113 0012630 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/hkeys
 */
class HKEYS extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'HKEYS';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/CuckooFilter/CFLOADCHUNK.php                                               0000644                 00000001156 15233650113 0016072 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\CuckooFilter;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/cf.loadchunk/
 *
 * Restores a filter previously saved using SCANDUMP.
 * See the SCANDUMP command for example usage.
 */
class CFLOADCHUNK extends RedisCommand
{
    public function getId()
    {
        return 'CF.LOADCHUNK';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/CuckooFilter/CFSCANDUMP.php                                                0000644                 00000001236 15233650113 0015773 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\CuckooFilter;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/cf.scandump/
 *
 * Begins an incremental save of the cuckoo filter.
 * This is useful for large cuckoo filters which cannot fit into the normal DUMP and RESTORE model.
 */
class CFSCANDUMP extends RedisCommand
{
    public function getId()
    {
        return 'CF.SCANDUMP';
    }
}
                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/CuckooFilter/CFINSERT.php                                                  0000644                 00000002405 15233650113 0015564 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\CuckooFilter;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\BloomFilters\Capacity;
use Predis\Command\Traits\BloomFilters\Items;
use Predis\Command\Traits\BloomFilters\NoCreate;

class CFINSERT extends RedisCommand
{
    use Capacity {
        Capacity::setArguments as setCapacity;
    }
    use NoCreate {
        NoCreate::setArguments as setNoCreate;
    }
    use Items {
        Items::setArguments as setItems;
    }

    protected static $capacityArgumentPositionOffset = 1;
    protected static $noCreateArgumentPositionOffset = 2;
    protected static $itemsArgumentPositionOffset = 3;

    public function getId()
    {
        return 'CF.INSERT';
    }

    public function setArguments(array $arguments)
    {
        $this->setNoCreate($arguments);
        $arguments = $this->getArguments();

        $this->setItems($arguments);
        $arguments = $this->getArguments();

        $this->setCapacity($arguments);
        $this->filterArguments();
    }
}
                                                                                                                                                                                                                                                           predis/src/Command/Redis/CuckooFilter/CFINSERTNX.php                                                0000644                 00000001131 15233650113 0016025 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\CuckooFilter;

/**
 * @see https://redis.io/commands/cf.insertnx/
 *
 * Adds one or more items to a cuckoo filter, allowing the filter
 * to be created with a custom capacity if it does not exist yet.
 */
class CFINSERTNX extends CFINSERT
{
    public function getId()
    {
        return 'CF.INSERTNX';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                       predis/src/Command/Redis/CuckooFilter/CFEXISTS.php                                                  0000644                 00000001063 15233650113 0015576 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\CuckooFilter;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/cf.exists/
 *
 * Check if an item exists in a Cuckoo Filter key.
 */
class CFEXISTS extends RedisCommand
{
    public function getId()
    {
        return 'CF.EXISTS';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                             predis/src/Command/Redis/CuckooFilter/CFADDNX.php                                                   0000644                 00000001106 15233650113 0015413 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\CuckooFilter;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/cf.addnx/
 *
 * Adds an item to a cuckoo filter if the item did not exist previously.
 */
class CFADDNX extends RedisCommand
{
    public function getId()
    {
        return 'CF.ADDNX';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                          predis/src/Command/Redis/CuckooFilter/CFMEXISTS.php                                                 0000644                 00000001100 15233650113 0015703 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\CuckooFilter;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/cf.mexists/
 *
 * Check if one or more items exists in a Cuckoo Filter key.
 */
class CFMEXISTS extends RedisCommand
{
    public function getId()
    {
        return 'CF.MEXISTS';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                predis/src/Command/Redis/CuckooFilter/CFADD.php                                                     0000644                 00000001107 15233650113 0015146 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\CuckooFilter;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/cf.add/
 *
 * Adds an item to the cuckoo filter, creating the filter if it does not exist.
 */
class CFADD extends RedisCommand
{
    public function getId()
    {
        return 'CF.ADD';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                         predis/src/Command/Redis/CuckooFilter/CFDEL.php                                                     0000644                 00000001250 15233650113 0015161 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\CuckooFilter;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/cf.del/
 *
 * Deletes an item once from the filter.
 * If the item exists only once, it will be removed from the filter.
 * If the item was added multiple times, it will still be present.
 */
class CFDEL extends RedisCommand
{
    public function getId()
    {
        return 'CF.DEL';
    }
}
                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/CuckooFilter/CFCOUNT.php                                                   0000644                 00000001223 15233650113 0015445 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\CuckooFilter;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/cf.count/
 *
 * Returns the number of times an item may be in the filter.
 * Because this is a probabilistic data structure, this may not necessarily be accurate.
 */
class CFCOUNT extends RedisCommand
{
    public function getId()
    {
        return 'CF.COUNT';
    }
}
                                                                                                                                                                                                                                                                                                                                                                             predis/src/Command/Redis/CuckooFilter/CFINFO.php                                                    0000644                 00000001642 15233650113 0015315 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\CuckooFilter;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/cf.info/
 *
 * Return information about key
 */
class CFINFO extends RedisCommand
{
    public function getId()
    {
        return 'CF.INFO';
    }

    public function parseResponse($data)
    {
        if (count($data) > 1) {
            $result = [];

            for ($i = 0, $iMax = count($data); $i < $iMax; ++$i) {
                if (array_key_exists($i + 1, $data)) {
                    $result[(string) $data[$i]] = $data[++$i];
                }
            }

            return $result;
        }

        return $data;
    }
}
                                                                                              predis/src/Command/Redis/CuckooFilter/CFRESERVE.php                                                 0000644                 00000002511 15233650113 0015671 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\CuckooFilter;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\BloomFilters\BucketSize;
use Predis\Command\Traits\BloomFilters\Expansion;
use Predis\Command\Traits\BloomFilters\MaxIterations;

class CFRESERVE extends RedisCommand
{
    use BucketSize {
        BucketSize::setArguments as setBucketSize;
    }
    use MaxIterations {
        MaxIterations::setArguments as setMaxIterations;
    }
    use Expansion {
        Expansion::setArguments as setExpansion;
    }

    protected static $bucketSizeArgumentPositionOffset = 2;
    protected static $maxIterationsArgumentPositionOffset = 3;
    protected static $expansionArgumentPositionOffset = 4;

    public function getId()
    {
        return 'CF.RESERVE';
    }

    public function setArguments(array $arguments)
    {
        $this->setExpansion($arguments);
        $arguments = $this->getArguments();

        $this->setMaxIterations($arguments);
        $arguments = $this->getArguments();

        $this->setBucketSize($arguments);
        $this->filterArguments();
    }
}
                                                                                                                                                                                       predis/src/Command/Redis/BLMOVE.php                                                                 0000644                 00000000602 15233650113 0012737 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

class BLMOVE extends LMOVE
{
    public function getId()
    {
        return 'BLMOVE';
    }
}
                                                                                                                              predis/src/Command/Redis/ZINTER.php                                                                 0000644                 00000001446 15233650113 0012775 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Traits\With\WithScores;

/**
 * @see https://redis.io/commands/zinter/
 *
 * This command is similar to ZINTERSTORE, but instead of
 * storing the resulting sorted set, it is returned to the client.
 */
class ZINTER extends ZINTERSTORE
{
    use WithScores;

    protected static $keysArgumentPositionOffset = 0;
    protected static $weightsArgumentPositionOffset = 1;
    protected static $aggregateArgumentPositionOffset = 2;

    public function getId()
    {
        return 'ZINTER';
    }
}
                                                                                                                                                                                                                          predis/src/Command/Redis/TDigest/TDIGESTBYRANK.php                                                  0000644                 00000002332 15233650113 0015332 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TDigest;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/tdigest.byrank/
 *
 * Returns, for each input rank, an estimation of the value (floating-point) with that rank.
 */
class TDIGESTBYRANK extends RedisCommand
{
    public function getId()
    {
        return 'TDIGEST.BYRANK';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        if (!is_array($data)) {
            return $data;
        }

        // convert Relay (RESP3) constants to strings
        return array_map(function ($value) {
            if (is_string($value) || !is_float($value)) {
                return $value;
            }

            if (is_nan($value)) {
                return 'nan';
            }

            switch ($value) {
                case INF: return 'inf';
                case -INF: return '-inf';
                default: return $value;
            }
        }, $data);
    }
}
                                                                                                                                                                                                                                                                                                      predis/src/Command/Redis/TDigest/TDIGESTMAX.php                                                     0000644                 00000001776 15233650113 0015004 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TDigest;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/tdigest.max/
 *
 * Returns the maximum observation value from a t-digest sketch.
 */
class TDIGESTMAX extends RedisCommand
{
    public function getId()
    {
        return 'TDIGEST.MAX';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        if (is_string($data) || !is_float($data)) {
            return $data;
        }

        // convert Relay (RESP3) constants to strings
        if (is_nan($data)) {
            return 'nan';
        }

        switch ($data) {
            case INF: return 'inf';
            case -INF: return '-inf';
            default: return $data;
        }
    }
}
  predis/src/Command/Redis/TDigest/TDIGESTMERGE.php                                                   0000644                 00000002175 15233650113 0015210 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TDigest;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/tdigest.merge/
 *
 * Merges multiple t-digest sketches into a single sketch.
 */
class TDIGESTMERGE extends RedisCommand
{
    public function getId()
    {
        return 'TDIGEST.MERGE';
    }

    public function setArguments(array $arguments)
    {
        $processedArguments = array_merge([$arguments[0], count($arguments[1])], $arguments[1]);

        for ($i = 2, $iMax = count($arguments); $i < $iMax; $i++) {
            if (is_int($arguments[$i]) && $arguments[$i] !== 0) {
                array_push($processedArguments, 'COMPRESSION', $arguments[$i]);
            } elseif (is_bool($arguments[$i]) && $arguments[$i]) {
                $processedArguments[] = 'OVERRIDE';
            }
        }

        parent::setArguments($processedArguments);
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                   predis/src/Command/Redis/TDigest/TDIGESTQUANTILE.php                                                0000644                 00000002415 15233650113 0015570 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TDigest;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/tdigest.quantile/
 *
 * Returns, for each input fraction, an estimation of the value (floating point) that is smaller than the given fraction of observations.
 */
class TDIGESTQUANTILE extends RedisCommand
{
    public function getId()
    {
        return 'TDIGEST.QUANTILE';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        if (!is_array($data)) {
            return $data;
        }

        // convert Relay (RESP3) constants to strings
        return array_map(function ($value) {
            if (is_string($value) || !is_float($value)) {
                return $value;
            }

            if (is_nan($value)) {
                return 'nan';
            }

            switch ($value) {
                case INF: return 'inf';
                case -INF: return '-inf';
                default: return $value;
            }
        }, $data);
    }
}
                                                                                                                                                                                                                                                   predis/src/Command/Redis/TDigest/TDIGESTBYREVRANK.php                                               0000644                 00000002363 15233650113 0015713 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TDigest;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/tdigest.byrevrank/
 *
 * Returns, for each input reverse rank, an estimation of the value (floating-point) with that reverse rank.
 */
class TDIGESTBYREVRANK extends RedisCommand
{
    public function getId()
    {
        return 'TDIGEST.BYREVRANK';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        if (!is_array($data)) {
            return $data;
        }

        // convert Relay (RESP3) constants to strings
        return array_map(function ($value) {
            if (is_string($value) || !is_float($value)) {
                return $value;
            }

            if (is_nan($value)) {
                return 'nan';
            }

            switch ($value) {
                case INF: return 'inf';
                case -INF: return '-inf';
                default: return $value;
            }
        }, $data);
    }
}
                                                                                                                                                                                                                                                                             predis/src/Command/Redis/TDigest/TDIGESTADD.php                                                     0000644                 00000001070 15233650113 0014732 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TDigest;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/tdigest.add/
 *
 * Adds one or more observations to a t-digest sketch.
 */
class TDIGESTADD extends RedisCommand
{
    public function getId()
    {
        return 'TDIGEST.ADD';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/TDigest/TDIGESTCDF.php                                                     0000644                 00000002454 15233650113 0014745 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TDigest;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/tdigest.cdf/
 *
 * Returns, for each input value, an estimation of the fraction (floating-point)
 * of (observations smaller than the given value + half
 * the observations equal to the given value).
 */
class TDIGESTCDF extends RedisCommand
{
    public function getId()
    {
        return 'TDIGEST.CDF';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        if (!is_array($data)) {
            return $data;
        }

        // convert Relay (RESP3) constants to strings
        return array_map(function ($value) {
            if (is_string($value) || !is_float($value)) {
                return $value;
            }

            if (is_nan($value)) {
                return 'nan';
            }

            switch ($value) {
                case INF: return 'inf';
                case -INF: return '-inf';
                default: return $value;
            }
        }, $data);
    }
}
                                                                                                                                                                                                                    predis/src/Command/Redis/TDigest/TDIGESTRESET.php                                                   0000644                 00000001114 15233650113 0015223 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TDigest;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/tdigest.reset/
 *
 * Resets a t-digest sketch: empty the sketch and re-initializes it.
 */
class TDIGESTRESET extends RedisCommand
{
    public function getId()
    {
        return 'TDIGEST.RESET';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                    predis/src/Command/Redis/TDigest/TDIGESTRANK.php                                                    0000644                 00000001347 15233650113 0015104 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TDigest;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/tdigest.rank/
 *
 * Returns, for each input value (floating-point), the estimated rank
 * of the value (the number of observations in the sketch that are smaller than
 * the value + half the number of observations that are equal to the value).
 */
class TDIGESTRANK extends RedisCommand
{
    public function getId()
    {
        return 'TDIGEST.RANK';
    }
}
                                                                                                                                                                                                                                                                                         predis/src/Command/Redis/TDigest/TDIGESTREVRANK.php                                                 0000644                 00000001367 15233650113 0015463 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TDigest;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/tdigest.revrank/
 *
 * Returns, for each input value (floating-point), the estimated reverse rank
 * of the value (the number of observations in the sketch that are larger than
 * the value + half the number of observations that are equal to the value).
 */
class TDIGESTREVRANK extends RedisCommand
{
    public function getId()
    {
        return 'TDIGEST.REVRANK';
    }
}
                                                                                                                                                                                                                                                                         predis/src/Command/Redis/TDigest/TDIGESTCREATE.php                                                  0000644                 00000001642 15233650113 0015312 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TDigest;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/tdigest.create/
 *
 * Allocates memory and initializes a new t-digest sketch.
 */
class TDIGESTCREATE extends RedisCommand
{
    public function getId()
    {
        return 'TDIGEST.CREATE';
    }

    public function setArguments(array $arguments)
    {
        if (!empty($arguments[1])) {
            $arguments[2] = $arguments[1];
            $arguments[1] = 'COMPRESSION';
        } elseif (array_key_exists(1, $arguments) && $arguments[1] < 1) {
            array_pop($arguments);
        }

        parent::setArguments($arguments);
    }
}
                                                                                              predis/src/Command/Redis/TDigest/TDIGESTINFO.php                                                    0000644                 00000001556 15233650113 0015106 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TDigest;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/tdigest.info/
 *
 * Returns information and statistics about a t-digest sketch.
 */
class TDIGESTINFO extends RedisCommand
{
    public function getId()
    {
        return 'TDIGEST.INFO';
    }

    public function parseResponse($data)
    {
        $result = [];

        for ($i = 0, $iMax = count($data); $i < $iMax; ++$i) {
            if (array_key_exists($i + 1, $data)) {
                $result[(string) $data[$i]] = $data[++$i];
            }
        }

        return $result;
    }
}
                                                                                                                                                  predis/src/Command/Redis/TDigest/TDIGESTTRIMMED_MEAN.php                                            0000644                 00000002137 15233650113 0016250 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TDigest;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/tdigest.trimmed_mean/
 *
 * Returns an estimation of the mean value from the sketch,
 * excluding observation values outside the low and high cutoff quantiles.
 */
class TDIGESTTRIMMED_MEAN extends RedisCommand
{
    public function getId()
    {
        return 'TDIGEST.TRIMMED_MEAN';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        if (is_string($data) || !is_float($data)) {
            return $data;
        }

        // convert Relay (RESP3) constants to strings
        if (is_nan($data)) {
            return 'nan';
        }

        switch ($data) {
            case INF: return 'inf';
            case -INF: return '-inf';
            default: return $data;
        }
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                 predis/src/Command/Redis/TDigest/TDIGESTMIN.php                                                     0000644                 00000001776 15233650113 0015002 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TDigest;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/tdigest.min/
 *
 * Returns the minimum observation value from a t-digest sketch.
 */
class TDIGESTMIN extends RedisCommand
{
    public function getId()
    {
        return 'TDIGEST.MIN';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        if (is_string($data) || !is_float($data)) {
            return $data;
        }

        // convert Relay (RESP3) constants to strings
        if (is_nan($data)) {
            return 'nan';
        }

        switch ($data) {
            case INF: return 'inf';
            case -INF: return '-inf';
            default: return $data;
        }
    }
}
  predis/src/Command/Redis/DISCARD.php                                                                0000644                 00000001016 15233650113 0013024 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/discard
 */
class DISCARD extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'DISCARD';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/SETBIT.php                                                                 0000644                 00000001013 15233650113 0012742 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/setbit
 */
class SETBIT extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SETBIT';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/SMEMBERS.php                                                               0000644                 00000001021 15233650113 0013164 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/smembers
 */
class SMEMBERS extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SMEMBERS';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               predis/src/Command/Redis/BRPOPLPUSH.php                                                             0000644                 00000001027 15233650113 0013453 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/brpoplpush
 */
class BRPOPLPUSH extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'BRPOPLPUSH';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         predis/src/Command/Redis/SORT.php                                                                   0000644                 00000003744 15233650113 0012554 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/sort
 */
class SORT extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SORT';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 1) {
            parent::setArguments($arguments);

            return;
        }

        $query = [$arguments[0]];
        $sortParams = array_change_key_case($arguments[1], CASE_UPPER);

        if (isset($sortParams['BY'])) {
            $query[] = 'BY';
            $query[] = $sortParams['BY'];
        }

        if (isset($sortParams['GET'])) {
            $getargs = $sortParams['GET'];

            if (is_array($getargs)) {
                foreach ($getargs as $getarg) {
                    $query[] = 'GET';
                    $query[] = $getarg;
                }
            } else {
                $query[] = 'GET';
                $query[] = $getargs;
            }
        }

        if (isset($sortParams['LIMIT'])
            && is_array($sortParams['LIMIT'])
            && count($sortParams['LIMIT']) == 2) {
            $query[] = 'LIMIT';
            $query[] = $sortParams['LIMIT'][0];
            $query[] = $sortParams['LIMIT'][1];
        }

        if (isset($sortParams['SORT'])) {
            $query[] = strtoupper($sortParams['SORT']);
        }

        if (isset($sortParams['ALPHA']) && $sortParams['ALPHA'] == true) {
            $query[] = 'ALPHA';
        }

        if (isset($sortParams['STORE'])) {
            $query[] = 'STORE';
            $query[] = $sortParams['STORE'];
        }

        parent::setArguments($query);
    }
}
                            predis/src/Command/Redis/SORT_RO.php                                                                0000644                 00000003456 15233650113 0013154 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\By\ByArgument;
use Predis\Command\Traits\Get\Get;
use Predis\Command\Traits\Limit\LimitObject;
use Predis\Command\Traits\Sorting;

/**
 * @see https://redis.io/commands/sort_ro/
 *
 * Read-only variant of the SORT command.
 * It is exactly like the original SORT but refuses the STORE option
 * and can safely be used in read-only replicas.
 */
class SORT_RO extends RedisCommand
{
    use ByArgument {
        ByArgument::setArguments as setBy;
    }
    use LimitObject {
        LimitObject::setArguments as setLimit;
    }
    use Get {
        Get::setArguments as setGetArgument;
    }
    use Sorting {
        Sorting::setArguments as setSorting;
    }

    protected static $byArgumentPositionOffset = 1;
    protected static $getArgumentPositionOffset = 3;
    protected static $sortArgumentPositionOffset = 4;

    public function getId()
    {
        return 'SORT_RO';
    }

    public function setArguments(array $arguments)
    {
        $alpha = array_pop($arguments);

        if (is_bool($alpha) && $alpha) {
            $arguments[] = 'ALPHA';
        } elseif (!is_bool($alpha)) {
            $arguments[] = $alpha;
        }

        $this->setSorting($arguments);
        $arguments = $this->getArguments();

        $this->setGetArgument($arguments);
        $arguments = $this->getArguments();

        $this->setLimit($arguments);
        $arguments = $this->getArguments();

        $this->setBy($arguments);
        $this->filterArguments();
    }
}
                                                                                                                                                                                                                  predis/src/Command/Redis/GETEX.php                                                                  0000644                 00000003052 15233650113 0012631 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use UnexpectedValueException;

class GETEX extends RedisCommand
{
    /**
     * @var string[]
     */
    private static $modifierEnum = [
        'ex' => 'EX',
        'px' => 'PX',
        'exat' => 'EXAT',
        'pxat' => 'PXAT',
        'persist' => 'PERSIST',
    ];

    public function getId()
    {
        return 'GETEX';
    }

    public function setArguments(array $arguments)
    {
        if (!array_key_exists(1, $arguments) || $arguments[1] === '') {
            parent::setArguments([$arguments[0]]);

            return;
        }

        if (!in_array(strtoupper($arguments[1]), self::$modifierEnum)) {
            $enumValues = implode(', ', array_keys(self::$modifierEnum));
            throw new UnexpectedValueException("Modifier argument accepts only: {$enumValues} values");
        }

        if ($arguments[1] === 'persist') {
            parent::setArguments([$arguments[0], self::$modifierEnum[$arguments[1]]]);

            return;
        }

        $arguments[1] = self::$modifierEnum[$arguments[1]];

        if (!array_key_exists(2, $arguments)) {
            throw new UnexpectedValueException('You should provide value for current modifier');
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      predis/src/Command/Redis/SINTERSTORE.php                                                            0000644                 00000001474 15233650113 0013604 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/sinterstore
 */
class SINTERSTORE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SINTERSTORE';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 2 && is_array($arguments[1])) {
            $arguments = array_merge([$arguments[0]], $arguments[1]);
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                    predis/src/Command/Redis/OBJECT_.php                                                                0000644                 00000001014 15233650113 0013056 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/object
 */
class OBJECT_ extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'OBJECT';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    predis/src/Command/Redis/XADD.php                                                                   0000644                 00000002631 15233650113 0012477 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/xadd
 */
class XADD extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'XADD';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $args = [];

        $args[] = $arguments[0];
        $options = $arguments[3] ?? [];

        if (isset($options['nomkstream']) && $options['nomkstream']) {
            $args[] = 'NOMKSTREAM';
        }

        if (isset($options['trim']) && is_array($options['trim'])) {
            array_push($args, ...$options['trim']);

            if (isset($options['limit'])) {
                $args[] = 'LIMIT';
                $args[] = $options['limit'];
            }
        }

        // ID, default to * to let Redis set it
        $args[] = $arguments[2] ?? '*';
        if (isset($arguments[1]) && is_array($arguments[1])) {
            foreach ($arguments[1] as $key => $val) {
                $args[] = $key;
                $args[] = $val;
            }
        }

        parent::setArguments($args);
    }
}
                                                                                                       predis/src/Command/Redis/CountMinSketch/CMSINITBYPROB.php                                           0000644                 00000001130 15233650113 0016672 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\CountMinSketch;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/cms.initbyprob/
 *
 * Initializes a Count-Min Sketch to accommodate requested tolerances.
 */
class CMSINITBYPROB extends RedisCommand
{
    public function getId()
    {
        return 'CMS.INITBYPROB';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/CountMinSketch/CMSINCRBY.php                                               0000644                 00000001144 15233650113 0016204 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\CountMinSketch;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/cms.incrby/
 *
 * Increases the count of item by increment.
 * Multiple items can be increased with one call.
 */
class CMSINCRBY extends RedisCommand
{
    public function getId()
    {
        return 'CMS.INCRBY';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                            predis/src/Command/Redis/CountMinSketch/CMSINITBYDIM.php                                            0000644                 00000001121 15233650113 0016541 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\CountMinSketch;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/cms.initbydim/
 *
 * Initializes a Count-Min Sketch to dimensions specified by user.
 */
class CMSINITBYDIM extends RedisCommand
{
    public function getId()
    {
        return 'CMS.INITBYDIM';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                               predis/src/Command/Redis/CountMinSketch/CMSMERGE.php                                                0000644                 00000002064 15233650113 0016057 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\CountMinSketch;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/cms.merge/
 *
 * Merges several sketches into one sketch.
 * All sketches must have identical width and depth.
 * Weights can be used to multiply certain sketches. Default weight is 1.
 */
class CMSMERGE extends RedisCommand
{
    public function getId()
    {
        return 'CMS.MERGE';
    }

    public function setArguments(array $arguments)
    {
        $processedArguments = array_merge([$arguments[0], count($arguments[1])], $arguments[1]);

        if (!empty($arguments[2])) {
            $processedArguments[] = 'WEIGHTS';
            $processedArguments = array_merge($processedArguments, $arguments[2]);
        }

        parent::setArguments($processedArguments);
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                            predis/src/Command/Redis/CountMinSketch/CMSINFO.php                                                 0000644                 00000001676 15233650113 0015763 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\CountMinSketch;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/cms.info/
 *
 * Returns width, depth and total count of the sketch.
 */
class CMSINFO extends RedisCommand
{
    public function getId()
    {
        return 'CMS.INFO';
    }

    public function parseResponse($data)
    {
        if (count($data) > 1) {
            $result = [];

            for ($i = 0, $iMax = count($data); $i < $iMax; ++$i) {
                if (array_key_exists($i + 1, $data)) {
                    $result[(string) $data[$i]] = $data[++$i];
                }
            }

            return $result;
        }

        return $data;
    }
}
                                                                  predis/src/Command/Redis/CountMinSketch/CMSQUERY.php                                                0000644                 00000001072 15233650113 0016123 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\CountMinSketch;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/cms.query/
 *
 * Returns the count for one or more items in a sketch.
 */
class CMSQUERY extends RedisCommand
{
    public function getId()
    {
        return 'CMS.QUERY';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                      predis/src/Command/Redis/SINTERCARD.php                                                             0000644                 00000001645 15233650113 0013421 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Keys;
use Predis\Command\Traits\Limit\Limit;

class SINTERCARD extends RedisCommand
{
    use Keys {
        Keys::setArguments as setKeys;
    }
    use Limit {
        Limit::setArguments as setLimit;
    }

    protected static $keysArgumentPositionOffset = 0;
    protected static $limitArgumentPositionOffset = 1;

    public function getId()
    {
        return 'SINTERCARD';
    }

    public function setArguments(array $arguments)
    {
        $this->setLimit($arguments);
        $arguments = $this->getArguments();

        $this->setKeys($arguments);
    }
}
                                                                                           predis/src/Command/Redis/GEORADIUSBYMEMBER.php                                                      0000644                 00000001317 15233650113 0014424 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

/**
 * @deprecated As of Redis version 6.2.0, this command is regarded as deprecated.
 *
 * It can be replaced by GEOSEARCH and GEOSEARCHSTORE with the FROMMEMBER arguments
 * when migrating or writing new code.
 *
 * @see http://redis.io/commands/georadiusbymember
 */
class GEORADIUSBYMEMBER extends GEORADIUS
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'GEORADIUSBYMEMBER';
    }
}
                                                                                                                                                                                                                                                                                                                 predis/src/Command/Redis/ACL.php                                                                    0000644                 00000002054 15233650113 0012355 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/?name=ACL
 *
 * Container command corresponds to any ACL *.
 * Represents any ACL command with subcommand as first argument.
 */
class ACL extends RedisCommand
{
    public function getId()
    {
        return 'ACL';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        if (!is_array($data)) {
            return $data;
        }

        if ($data === array_values($data)) {
            return $data;
        }

        // flatten Relay (RESP3) maps
        $return = [];

        array_walk($data, function ($value, $key) use (&$return) {
            $return[] = $key;
            $return[] = $value;
        });

        return $return;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    predis/src/Command/Redis/RENAME.php                                                                 0000644                 00000001013 15233650113 0012717 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/rename
 */
class RENAME extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'RENAME';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/HMSET.php                                                                  0000644                 00000001742 15233650113 0012641 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/hmset
 */
class HMSET extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'HMSET';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 2 && is_array($arguments[1])) {
            $flattenedKVs = [$arguments[0]];
            $args = $arguments[1];

            foreach ($args as $k => $v) {
                $flattenedKVs[] = $k;
                $flattenedKVs[] = $v;
            }

            $arguments = $flattenedKVs;
        }

        parent::setArguments($arguments);
    }
}
                              predis/src/Command/Redis/AUTH.php                                                                   0000644                 00000001005 15233650113 0012512 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/auth
 */
class AUTH extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'AUTH';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/ZREVRANGEBYSCORE.php                                                       0000644                 00000000775 15233650113 0014360 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

/**
 * @see http://redis.io/commands/zrevrangebyscore
 */
class ZREVRANGEBYSCORE extends ZRANGEBYSCORE
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZREVRANGEBYSCORE';
    }
}
   predis/src/Command/Redis/SENTINEL.php                                                               0000644                 00000002736 15233650113 0013206 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/topics/sentinel
 */
class SENTINEL extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SENTINEL';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        $argument = $this->getArgument(0);
        $argument = is_null($argument) ? null : strtolower($argument);

        switch ($argument) {
            case 'masters':
            case 'slaves':
                return self::processMastersOrSlaves($data);

            default:
                return $data;
        }
    }

    /**
     * Returns a processed response to SENTINEL MASTERS or SENTINEL SLAVES.
     *
     * @param array $servers List of Redis servers.
     *
     * @return array
     */
    protected static function processMastersOrSlaves(array $servers)
    {
        foreach ($servers as $idx => $node) {
            $processed = [];
            $count = count($node);

            for ($i = 0; $i < $count; ++$i) {
                $processed[$node[$i]] = $node[++$i];
            }

            $servers[$idx] = $processed;
        }

        return $servers;
    }
}
                                  predis/src/Command/Redis/HINCRBYFLOAT.php                                                           0000644                 00000001035 15233650113 0013640 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/hincrbyfloat
 */
class HINCRBYFLOAT extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'HINCRBYFLOAT';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   predis/src/Command/Redis/PFCOUNT.php                                                                0000644                 00000001331 15233650113 0013071 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/pfcount
 */
class PFCOUNT extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'PFCOUNT';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeArguments($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                       predis/src/Command/Redis/HMGET.php                                                                  0000644                 00000001322 15233650113 0012617 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/hmget
 */
class HMGET extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'HMGET';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeVariadic($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                              predis/src/Command/Redis/RANDOMKEY.php                                                              0000644                 00000001233 15233650113 0013305 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/randomkey
 */
class RANDOMKEY extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'RANDOMKEY';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        return $data !== '' ? $data : null;
    }
}
                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/HSTRLEN.php                                                                0000644                 00000001016 15233650113 0013072 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/hstrlen
 */
class HSTRLEN extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'HSTRLEN';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/HDEL.php                                                                   0000644                 00000001317 15233650113 0012473 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/hdel
 */
class HDEL extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'HDEL';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeVariadic($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                                 predis/src/Command/Redis/EXISTS.php                                                                 0000644                 00000001013 15233650113 0012767 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/exists
 */
class EXISTS extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'EXISTS';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/HGET.php                                                                   0000644                 00000001005 15233650113 0012500 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/hget
 */
class HGET extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'HGET';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/SETNX.php                                                                  0000644                 00000001010 15233650113 0012646 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/setnx
 */
class SETNX extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SETNX';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/GEOSEARCHSTORE.php                                                         0000644                 00000003345 15233650113 0014077 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\By\GeoBy;
use Predis\Command\Traits\Count;
use Predis\Command\Traits\From\GeoFrom;
use Predis\Command\Traits\Sorting;
use Predis\Command\Traits\Storedist;

/**
 * @see https://redis.io/commands/geosearchstore/
 *
 * This command is like GEOSEARCH, but stores the result in destination key.
 */
class GEOSEARCHSTORE extends RedisCommand
{
    use GeoFrom {
        GeoFrom::setArguments as setFrom;
    }
    use GeoBy {
        GeoBy::setArguments as setBy;
    }
    use Sorting {
        Sorting::setArguments as setSorting;
    }
    use Count {
        Count::setArguments as setCount;
    }
    use Storedist {
        Storedist::setArguments as setStoreDist;
    }

    protected static $sortArgumentPositionOffset = 4;
    protected static $countArgumentPositionOffset = 5;
    protected static $storeDistArgumentPositionOffset = 7;

    public function getId()
    {
        return 'GEOSEARCHSTORE';
    }

    public function setArguments(array $arguments)
    {
        $this->setStoreDist($arguments);
        $arguments = $this->getArguments();

        $this->setCount($arguments, $arguments[6] ?? false);
        $arguments = $this->getArguments();

        $this->setSorting($arguments);
        $arguments = $this->getArguments();

        $this->setFrom($arguments);
        $arguments = $this->getArguments();

        $this->setBy($arguments);
        $this->filterArguments();
    }
}
                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/LPUSH.php                                                                  0000644                 00000001322 15233650113 0012646 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/lpush
 */
class LPUSH extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'LPUSH';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeVariadic($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                              predis/src/Command/Redis/CLIENT.php                                                                 0000644                 00000003220 15233650113 0012730 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/client-list
 * @see http://redis.io/commands/client-kill
 * @see http://redis.io/commands/client-getname
 * @see http://redis.io/commands/client-setname
 */
class CLIENT extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'CLIENT';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        $args = array_change_key_case($this->getArguments(), CASE_UPPER);

        switch (strtoupper($args[0])) {
            case 'LIST':
                return $this->parseClientList($data);
            case 'KILL':
            case 'GETNAME':
            case 'SETNAME':
            default:
                return $data;
        } // @codeCoverageIgnore
    }

    /**
     * Parses the response to CLIENT LIST and returns a structured list.
     *
     * @param string $data Response buffer.
     *
     * @return array
     */
    protected function parseClientList($data)
    {
        $clients = [];

        foreach (explode("\n", $data, -1) as $clientData) {
            $client = [];

            foreach (explode(' ', $clientData) as $kv) {
                @[$k, $v] = explode('=', $kv);
                $client[$k] = $v;
            }

            $clients[] = $client;
        }

        return $clients;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                predis/src/Command/Redis/RPOPLPUSH.php                                                              0000644                 00000001024 15233650113 0013346 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/rpoplpush
 */
class RPOPLPUSH extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'RPOPLPUSH';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            predis/src/Command/Redis/BLPOP.php                                                                  0000644                 00000001503 15233650113 0012630 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/blpop
 */
class BLPOP extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'BLPOP';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 2 && is_array($arguments[0])) {
            [$arguments, $timeout] = $arguments;
            array_push($arguments, $timeout);
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                             predis/src/Command/Redis/EXPIRE.php                                                                 0000644                 00000001417 15233650113 0012754 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Expire\ExpireOptions;

/**
 * @see http://redis.io/commands/expire
 *
 * Set a timeout on key.
 * After the timeout has expired, the key will automatically be deleted.
 * A key with an associated timeout is often said to be volatile in Redis terminology.
 */
class EXPIRE extends RedisCommand
{
    use ExpireOptions;

    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'EXPIRE';
    }
}
                                                                                                                                                                                                                                                 predis/src/Command/Redis/XREVRANGE.php                                                              0000644                 00000000741 15233650113 0013320 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

/**
 * @see http://redis.io/commands/xrevrange
 */
class XREVRANGE extends XRANGE
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'XREVRANGE';
    }
}
                               predis/src/Command/Redis/SCAN.php                                                                   0000644                 00000002715 15233650113 0012506 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/scan
 */
class SCAN extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SCAN';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 2 && is_array($arguments[1])) {
            $options = $this->prepareOptions(array_pop($arguments));
            $arguments = array_merge($arguments, $options);
        }

        parent::setArguments($arguments);
    }

    /**
     * Returns a list of options and modifiers compatible with Redis.
     *
     * @param array $options List of options.
     *
     * @return array
     */
    protected function prepareOptions($options)
    {
        $options = array_change_key_case($options, CASE_UPPER);
        $normalized = [];

        if (!empty($options['MATCH'])) {
            $normalized[] = 'MATCH';
            $normalized[] = $options['MATCH'];
        }

        if (!empty($options['COUNT'])) {
            $normalized[] = 'COUNT';
            $normalized[] = $options['COUNT'];
        }

        return $normalized;
    }
}
                                                   predis/src/Command/Redis/XLEN.php                                                                   0000644                 00000001005 15233650113 0012517 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/xlen
 */
class XLEN extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'XLEN';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/SDIFF.php                                                                  0000644                 00000001323 15233650113 0012607 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/sdiff
 */
class SDIFF extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SDIFF';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeArguments($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                             predis/src/Command/Redis/EXPIRETIME.php                                                             0000644                 00000001150 15233650113 0013425 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/expiretime/
 *
 * Returns the absolute Unix timestamp (since January 1, 1970)
 * in seconds at which the given key will expire.
 */
class EXPIRETIME extends RedisCommand
{
    public function getId()
    {
        return 'EXPIRETIME';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/PEXPIRE.php                                                                0000644                 00000001016 15233650113 0013067 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/pexpire
 */
class PEXPIRE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'PEXPIRE';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/SET.php                                                                    0000644                 00000001002 15233650113 0012401 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/set
 */
class SET extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SET';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              predis/src/Command/Redis/LMPOP.php                                                                  0000644                 00000002527 15233650113 0012652 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Count;
use Predis\Command\Traits\Keys;
use Predis\Command\Traits\LeftRight;

class LMPOP extends RedisCommand
{
    use Keys {
        Keys::setArguments as setKeys;
    }
    use LeftRight {
        LeftRight::setArguments as setLeftRight;
    }
    use Count {
        Count::setArguments as setCount;
    }

    protected static $keysArgumentPositionOffset = 0;
    protected static $leftRightArgumentPositionOffset = 1;
    protected static $countArgumentPositionOffset = 2;

    public function getId()
    {
        return 'LMPOP';
    }

    public function setArguments(array $arguments)
    {
        $this->setCount($arguments);
        $arguments = $this->getArguments();

        $this->setLeftRight($arguments);
        $arguments = $this->getArguments();

        $this->setKeys($arguments);
        $this->filterArguments();
    }

    public function parseResponse($data)
    {
        if (null === $data) {
            return null;
        }

        return [$data[0] => $data[1]];
    }
}
                                                                                                                                                                         predis/src/Command/Redis/LLEN.php                                                                   0000644                 00000001005 15233650113 0012503 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/llen
 */
class LLEN extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'LLEN';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/SETEX.php                                                                  0000644                 00000001010 15233650113 0012635 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/setex
 */
class SETEX extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SETEX';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/BGSAVE.php                                                                 0000644                 00000001253 15233650113 0012725 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/bgsave
 */
class BGSAVE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'BGSAVE';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        return $data === 'Background saving started' ? true : $data;
    }
}
                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/GETDEL.php                                                                 0000644                 00000000666 15233650113 0012731 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

class GETDEL extends RedisCommand
{
    public function getId()
    {
        return 'GETDEL';
    }
}
                                                                          predis/src/Command/Redis/SLOWLOG.php                                                                0000644                 00000001775 15233650113 0013115 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/slowlog
 */
class SLOWLOG extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SLOWLOG';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        if (is_array($data)) {
            $log = [];

            foreach ($data as $index => $entry) {
                $log[$index] = [
                    'id' => $entry[0],
                    'timestamp' => $entry[1],
                    'duration' => $entry[2],
                    'command' => $entry[3],
                ];
            }

            return $log;
        }

        return $data;
    }
}
   predis/src/Command/Redis/CONFIG.php                                                                 0000644                 00000002113 15233650113 0012717 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/config-set
 * @see http://redis.io/commands/config-get
 * @see http://redis.io/commands/config-resetstat
 * @see http://redis.io/commands/config-rewrite
 */
class CONFIG extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'CONFIG';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        if (is_array($data)) {
            if ($data !== array_values($data)) {
                return $data; // Relay
            }

            $result = [];

            for ($i = 0; $i < count($data); ++$i) {
                $result[$data[$i]] = $data[++$i];
            }

            return $result;
        }

        return $data;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/RENAMENX.php                                                               0000644                 00000001021 15233650113 0013164 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/renamenx
 */
class RENAMENX extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'RENAMENX';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               predis/src/Command/Redis/ZINCRBY.php                                                                0000644                 00000001016 15233650113 0013073 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/zincrby
 */
class ZINCRBY extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZINCRBY';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/BITOP.php                                                                  0000644                 00000001602 15233650113 0012631 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/bitop
 */
class BITOP extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'BITOP';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 3 && is_array($arguments[2])) {
            [$operation, $destination] = $arguments;
            $arguments = $arguments[2];
            array_unshift($arguments, $operation, $destination);
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                              predis/src/Command/Redis/XTRIM.php                                                                  0000644                 00000002130 15233650113 0012654 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/xtrim
 */
class XTRIM extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'XTRIM';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $args = [];
        $options = $arguments[3] ?? [];

        $args[] = $arguments[0];
        // Either e.g. 'MAXLEN' or ['MAXLEN', '~']
        if (is_array($arguments[1])) {
            array_push($args, ...$arguments[1]);
        } else {
            $args[] = $arguments[1];
        }

        $args[] = $arguments[2];
        if (isset($options['limit'])) {
            $args[] = 'LIMIT';
            $args[] = $options['limit'];
        }

        parent::setArguments($args);
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/ZINTERSTORE.php                                                            0000644                 00000000754 15233650113 0013613 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

/**
 * @see http://redis.io/commands/zinterstore
 */
class ZINTERSTORE extends ZUNIONSTORE
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZINTERSTORE';
    }
}
                    predis/src/Command/Redis/DECRBY.php                                                                 0000644                 00000001013 15233650113 0012720 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/decrby
 */
class DECRBY extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'DECRBY';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/GEOHASH.php                                                                0000644                 00000001524 15233650113 0013035 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/geohash
 */
class GEOHASH extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'GEOHASH';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 2 && is_array($arguments[1])) {
            $members = array_pop($arguments);
            $arguments = array_merge($arguments, $members);
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                            predis/src/Command/Redis/ZINTERCARD.php                                                             0000644                 00000002137 15233650113 0013425 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Keys;
use Predis\Command\Traits\Limit\Limit;

/**
 * @see https://redis.io/commands/zintercard/
 *
 * This command is similar to ZINTER, but instead of returning the result set,
 * it returns just the cardinality of the result.
 */
class ZINTERCARD extends RedisCommand
{
    use Keys {
        Keys::setArguments as setKeys;
    }
    use Limit {
        Limit::setArguments as setLimit;
    }

    protected static $keysArgumentPositionOffset = 0;
    protected static $limitArgumentPositionOffset = 1;

    public function getId()
    {
        return 'ZINTERCARD';
    }

    public function setArguments(array $arguments)
    {
        $this->setLimit($arguments);
        $arguments = $this->getArguments();

        $this->setKeys($arguments);
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                 predis/src/Command/Redis/PTTL.php                                                                   0000644                 00000001005 15233650113 0012534 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/pttl
 */
class PTTL extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'PTTL';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/ZUNION.php                                                                 0000644                 00000001446 15233650113 0013004 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Traits\With\WithScores;

/**
 * @see https://redis.io/commands/zunion/
 *
 * This command is similar to ZUNIONSTORE, but instead of
 * storing the resulting sorted set, it is returned to the client.
 */
class ZUNION extends ZUNIONSTORE
{
    use WithScores;

    protected static $keysArgumentPositionOffset = 0;
    protected static $weightsArgumentPositionOffset = 1;
    protected static $aggregateArgumentPositionOffset = 2;

    public function getId()
    {
        return 'ZUNION';
    }
}
                                                                                                                                                                                                                          predis/src/Command/Redis/PERSIST.php                                                                0000644                 00000001016 15233650113 0013104 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/persist
 */
class PERSIST extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'PERSIST';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/FLUSHALL.php                                                               0000644                 00000001021 15233650113 0013161 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/flushall
 */
class FLUSHALL extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'FLUSHALL';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               predis/src/Command/Redis/ECHO_.php                                                                  0000644                 00000001006 15233650113 0012627 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/echo
 */
class ECHO_ extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ECHO';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          predis/src/Command/Redis/SELECT.php                                                                 0000644                 00000001013 15233650113 0012727 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/select
 */
class SELECT extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SELECT';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/Json/JSONTYPE.php                                                          0000644                 00000001041 15233650113 0014135 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.type/
 *
 * Report the type of JSON value at path
 */
class JSONTYPE extends RedisCommand
{
    public function getId()
    {
        return 'JSON.TYPE';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               predis/src/Command/Redis/Json/JSONNUMINCRBY.php                                                     0000644                 00000001076 15233650113 0014732 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.numincrby/
 *
 * Increment the number value stored at path by number
 */
class JSONNUMINCRBY extends RedisCommand
{
    public function getId()
    {
        return 'JSON.NUMINCRBY';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/Json/JSONDEL.php                                                           0000644                 00000001007 15233650113 0013762 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.del/
 *
 * Delete a value
 */
class JSONDEL extends RedisCommand
{
    public function getId()
    {
        return 'JSON.DEL';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         predis/src/Command/Redis/Json/JSONTOGGLE.php                                                        0000644                 00000001047 15233650113 0014343 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.toggle/
 *
 * Toggle a Boolean value stored at path
 */
class JSONTOGGLE extends RedisCommand
{
    public function getId()
    {
        return 'JSON.TOGGLE';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         predis/src/Command/Redis/Json/JSONSET.php                                                           0000644                 00000001517 15233650113 0014017 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Json\NxXxArgument;

/**
 * @see https://redis.io/commands/json.set/
 *
 * Set the JSON value at path in key
 */
class JSONSET extends RedisCommand
{
    use NxXxArgument {
        setArguments as setSubcommand;
    }

    protected static $nxXxArgumentPositionOffset = 3;

    public function getId()
    {
        return 'JSON.SET';
    }

    public function setArguments(array $arguments)
    {
        $this->setSubcommand($arguments);
        $this->filterArguments();
    }
}
                                                                                                                                                                                 predis/src/Command/Redis/Json/JSONDEBUG.php                                                         0000644                 00000001067 15233650113 0014212 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.debug/
 *
 * This is a container command for debugging related tasks.
 */
class JSONDEBUG extends RedisCommand
{
    public function getId()
    {
        return 'JSON.DEBUG';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                         predis/src/Command/Redis/Json/JSONARRINDEX.php                                                      0000644                 00000001103 15233650113 0014567 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.arrindex/
 *
 * Search for the first occurrence of a JSON value in an array
 */
class JSONARRINDEX extends RedisCommand
{
    public function getId()
    {
        return 'JSON.ARRINDEX';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                             predis/src/Command/Redis/Json/JSONCLEAR.php                                                         0000644                 00000001102 15233650113 0014200 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.clear/
 *
 * Clear container values (arrays/objects) and set numeric values to 0
 */
class JSONCLEAR extends RedisCommand
{
    public function getId()
    {
        return 'JSON.CLEAR';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                              predis/src/Command/Redis/Json/JSONARRPOP.php                                                        0000644                 00000001072 15233650113 0014363 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.arrpop/
 *
 * Remove and return an element from the index in the array
 */
class JSONARRPOP extends RedisCommand
{
    public function getId()
    {
        return 'JSON.ARRPOP';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                      predis/src/Command/Redis/Json/JSONGET.php                                                           0000644                 00000002474 15233650113 0014006 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Json\Indent;
use Predis\Command\Traits\Json\Newline;
use Predis\Command\Traits\Json\Space;

/**
 * @see https://redis.io/commands/json.get/
 *
 * Return the value at path in JSON serialized form
 */
class JSONGET extends RedisCommand
{
    use Indent {
        Indent::setArguments as setIndent;
    }
    use Newline {
        Newline::setArguments as setNewline;
    }
    use Space {
        Space::setArguments as setSpace;
    }

    protected static $indentArgumentPositionOffset = 1;
    protected static $newlineArgumentPositionOffset = 2;
    protected static $spaceArgumentPositionOffset = 3;

    public function getId()
    {
        return 'JSON.GET';
    }

    public function setArguments(array $arguments)
    {
        $this->setSpace($arguments);
        $arguments = $this->getArguments();

        $this->setNewline($arguments);
        $arguments = $this->getArguments();

        $this->setIndent($arguments);
        $this->filterArguments();
    }
}
                                                                                                                                                                                                    predis/src/Command/Redis/Json/JSONMGET.php                                                          0000644                 00000001341 15233650113 0014113 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

class JSONMGET extends RedisCommand
{
    public function getId()
    {
        return 'JSON.MGET';
    }

    public function setArguments(array $arguments)
    {
        $unpackedArguments = [];

        foreach ($arguments[0] as $key) {
            $unpackedArguments[] = $key;
        }

        $unpackedArguments[] = $arguments[1];

        parent::setArguments($unpackedArguments);
    }
}
                                                                                                                                                                                                                                                                                               predis/src/Command/Redis/Json/JSONARRINSERT.php                                                     0000644                 00000001137 15233650113 0014733 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.arrinsert/
 *
 * Insert the json values into the array at path before the index (shifts to the right)
 */
class JSONARRINSERT extends RedisCommand
{
    public function getId()
    {
        return 'JSON.ARRINSERT';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                 predis/src/Command/Redis/Json/JSONOBJKEYS.php                                                       0000644                 00000001074 15233650113 0014470 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.objkeys/
 *
 * Return the keys in the object that's referenced by path
 */
class JSONOBJKEYS extends RedisCommand
{
    public function getId()
    {
        return 'JSON.OBJKEYS';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                    predis/src/Command/Redis/Json/JSONARRTRIM.php                                                       0000644                 00000001125 15233650113 0014477 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.arrtrim/
 *
 * Trim an array so that it contains only the specified inclusive range of elements
 */
class JSONARRTRIM extends RedisCommand
{
    public function getId()
    {
        return 'JSON.ARRTRIM';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/Json/JSONFORGET.php                                                        0000644                 00000001052 15233650113 0014344 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.forget/
 *
 * @see https://redis.io/commands/json.del/
 */
class JSONFORGET extends RedisCommand
{
    public function getId()
    {
        return 'JSON.FORGET';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      predis/src/Command/Redis/Json/JSONOBJLEN.php                                                        0000644                 00000001075 15233650113 0014334 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.objlen/
 *
 * Report the number of keys in the JSON object at path in key
 */
class JSONOBJLEN extends RedisCommand
{
    public function getId()
    {
        return 'JSON.OBJLEN';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                   predis/src/Command/Redis/Json/JSONRESP.php                                                          0000644                 00000001105 15233650113 0014126 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.resp/
 *
 * Return the JSON in key in Redis serialization protocol specification form
 */
class JSONRESP extends RedisCommand
{
    public function getId()
    {
        return 'JSON.RESP';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/Json/JSONMSET.php                                                          0000644                 00000001125 15233650113 0014127 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.mset/
 *
 * Set or update one or more JSON values according to the specified key-path-value triplets.
 */
class JSONMSET extends RedisCommand
{
    public function getId()
    {
        return 'JSON.MSET';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/Json/JSONSTRLEN.php                                                        0000644                 00000001065 15233650113 0014371 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.strlen/
 *
 * Report the length of the JSON String at path in key
 */
class JSONSTRLEN extends RedisCommand
{
    public function getId()
    {
        return 'JSON.STRLEN';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/Json/JSONARRLEN.php                                                        0000644                 00000001064 15233650113 0014344 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.arrlen/
 *
 * Report the length of the JSON array at path in key
 */
class JSONARRLEN extends RedisCommand
{
    public function getId()
    {
        return 'JSON.ARRLEN';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                            predis/src/Command/Redis/Json/JSONARRAPPEND.php                                                     0000644                 00000001125 15233650113 0014673 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.arrappend/
 *
 * Append the json values into the array at path after the last element in it
 */
class JSONARRAPPEND extends RedisCommand
{
    public function getId()
    {
        return 'JSON.ARRAPPEND';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/Json/JSONMERGE.php                                                         0000644                 00000001220 15233650113 0014212 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.merge/
 *
 * Merge a given JSON value into matching paths.
 * Consequently, JSON values at matching paths are updated, deleted, or expanded with new children.
 */
class JSONMERGE extends RedisCommand
{
    public function getId()
    {
        return 'JSON.MERGE';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                predis/src/Command/Redis/Json/JSONSTRAPPEND.php                                                     0000644                 00000001076 15233650113 0014724 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\Json;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/json.strappend/
 *
 * Append the json-string values to the string at path
 */
class JSONSTRAPPEND extends RedisCommand
{
    public function getId()
    {
        return 'JSON.STRAPPEND';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/PUBSUB.php                                                                 0000644                 00000002321 15233650113 0012753 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/pubsub
 */
class PUBSUB extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'PUBSUB';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        switch (strtolower($this->getArgument(0))) {
            case 'numsub':
                return self::processNumsub($data);

            default:
                return $data;
        }
    }

    /**
     * Returns the processed response to PUBSUB NUMSUB.
     *
     * @param array $channels List of channels
     *
     * @return array
     */
    protected static function processNumsub(array $channels)
    {
        $processed = [];
        $count = count($channels);

        for ($i = 0; $i < $count; ++$i) {
            $processed[$channels[$i]] = $channels[++$i];
        }

        return $processed;
    }
}
                                                                                                                                                                                                                                                                                                               predis/src/Command/Redis/MGET.php                                                                   0000644                 00000001320 15233650113 0012505 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/mget
 */
class MGET extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'MGET';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeArguments($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                                predis/src/Command/Redis/INCRBY.php                                                                 0000644                 00000001013 15233650113 0012736 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/incrby
 */
class INCRBY extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'INCRBY';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/TOUCH.php                                                                  0000644                 00000001323 15233650113 0012636 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/touch
 */
class TOUCH extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'TOUCH';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeArguments($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                             predis/src/Command/Redis/BITCOUNT.php                                                               0000644                 00000001214 15233650113 0013202 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\BitByte;

/**
 * @see http://redis.io/commands/bitcount
 *
 * Count the number of set bits (population counting) in a string.
 */
class BITCOUNT extends RedisCommand
{
    use BitByte;

    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'BITCOUNT';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                    predis/src/Command/Redis/SAVE.php                                                                   0000644                 00000001005 15233650113 0012507 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/save
 */
class SAVE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SAVE';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/SCARD.php                                                                  0000644                 00000001010 15233650113 0012601 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/scard
 */
class SCARD extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SCARD';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/SCRIPT.php                                                                 0000644                 00000001013 15233650113 0012754 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/script
 */
class SCRIPT extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SCRIPT';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/TIME.php                                                                   0000644                 00000001005 15233650113 0012507 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/time
 */
class TIME extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'TIME';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/DBSIZE.php                                                                 0000644                 00000001013 15233650113 0012730 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/dbsize
 */
class DBSIZE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'DBSIZE';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/DEL.php                                                                    0000644                 00000001315 15233650113 0012361 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/del
 */
class DEL extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'DEL';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeArguments($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                                   predis/src/Command/Redis/PSUBSCRIBE.php                                                             0000644                 00000001342 15233650113 0013416 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/psubscribe
 */
class PSUBSCRIBE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'PSUBSCRIBE';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeArguments($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                              predis/src/Command/Redis/SISMEMBER.php                                                              0000644                 00000001024 15233650113 0013300 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/sismember
 */
class SISMEMBER extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SISMEMBER';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            predis/src/Command/Redis/LINSERT.php                                                                0000644                 00000001016 15233650113 0013073 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/linsert
 */
class LINSERT extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'LINSERT';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/ZRANGEBYLEX.php                                                            0000644                 00000002147 15233650113 0013553 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

/**
 * @see http://redis.io/commands/zrangebylex
 */
class ZRANGEBYLEX extends ZRANGE
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZRANGEBYLEX';
    }

    /**
     * {@inheritdoc}
     */
    protected function prepareOptions($options)
    {
        $opts = array_change_key_case($options, CASE_UPPER);
        $finalizedOpts = [];

        if (isset($opts['LIMIT']) && is_array($opts['LIMIT'])) {
            $limit = array_change_key_case($opts['LIMIT'], CASE_UPPER);

            $finalizedOpts[] = 'LIMIT';
            $finalizedOpts[] = $limit['OFFSET'] ?? $limit[0];
            $finalizedOpts[] = $limit['COUNT'] ?? $limit[1];
        }

        return $finalizedOpts;
    }

    /**
     * {@inheritdoc}
     */
    protected function withScores()
    {
        return false;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                         predis/src/Command/Redis/RESTORE.php                                                                0000644                 00000001016 15233650113 0013076 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/restore
 */
class RESTORE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'RESTORE';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/ZREVRANK.php                                                               0000644                 00000001021 15233650113 0013211 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/zrevrank
 */
class ZREVRANK extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZREVRANK';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               predis/src/Command/Redis/WAITAOF.php                                                                0000644                 00000001271 15233650113 0013050 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/waitaof/
 *
 * This command blocks the current client until all the previous write commands are acknowledged
 * as having been fsynced to the AOF of the local Redis and/or at least the specified number of replicas.
 */
class WAITAOF extends RedisCommand
{
    public function getId()
    {
        return 'WAITAOF';
    }
}
                                                                                                                                                                                                                                                                                                                                       predis/src/Command/Redis/ZREVRANGE.php                                                              0000644                 00000000741 15233650113 0013322 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

/**
 * @see http://redis.io/commands/zrevrange
 */
class ZREVRANGE extends ZRANGE
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZREVRANGE';
    }
}
                               predis/src/Command/Redis/KEYS.php                                                                   0000644                 00000001005 15233650113 0012524 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/keys
 */
class KEYS extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'KEYS';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/MULTI.php                                                                  0000644                 00000001010 15233650113 0012637 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/multi
 */
class MULTI extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'MULTI';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/SLAVEOF.php                                                                0000644                 00000001425 15233650113 0013056 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/slaveof
 */
class SLAVEOF extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SLAVEOF';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 0 || $arguments[0] === 'NO ONE') {
            $arguments = ['NO', 'ONE'];
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                           predis/src/Command/Redis/SPOP.php                                                                   0000644                 00000001005 15233650113 0012532 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/spop
 */
class SPOP extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SPOP';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/SUNION.php                                                                 0000644                 00000001326 15233650113 0012772 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/sunion
 */
class SUNION extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SUNION';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeArguments($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                          predis/src/Command/Redis/BGREWRITEAOF.php                                                           0000644                 00000001301 15233650113 0013630 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/bgrewriteaof
 */
class BGREWRITEAOF extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'BGREWRITEAOF';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        return $data == 'Background append only file rewriting started';
    }
}
                                                                                                                                                                                                                                                                                                                               predis/src/Command/Redis/FAILOVER.php                                                               0000644                 00000002114 15233650113 0013162 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Timeout;
use Predis\Command\Traits\To\ServerTo;

class FAILOVER extends RedisCommand
{
    use ServerTo {
        ServerTo::setArguments as setTo;
    }
    use Timeout {
        Timeout::setArguments as setTimeout;
    }

    protected static $toArgumentPositionOffset = 0;
    protected static $timeoutArgumentPositionOffset = 2;

    public function getId()
    {
        return 'FAILOVER';
    }

    public function setArguments(array $arguments)
    {
        if (array_key_exists(1, $arguments) && false !== $arguments[1]) {
            $arguments[1] = 'ABORT';
        }

        $this->setTimeout($arguments);
        $arguments = $this->getArguments();

        $this->setTo($arguments);
        $this->filterArguments();
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                    predis/src/Command/Redis/GEOADD.php                                                                 0000644                 00000001551 15233650113 0012702 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/geoadd
 */
class GEOADD extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'GEOADD';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 2 && is_array($arguments[1])) {
            foreach (array_pop($arguments) as $item) {
                $arguments = array_merge($arguments, $item);
            }
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                                                       predis/src/Command/Redis/SRANDMEMBER.php                                                            0000644                 00000001032 15233650113 0013510 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/srandmember
 */
class SRANDMEMBER extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SRANDMEMBER';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      predis/src/Command/Redis/EXEC.php                                                                   0000644                 00000001005 15233650113 0012475 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/exec
 */
class EXEC extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'EXEC';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/DECR.php                                                                   0000644                 00000001005 15233650113 0012466 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/decr
 */
class DECR extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'DECR';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/GETRANGE.php                                                               0000644                 00000001021 15233650113 0013143 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/getrange
 */
class GETRANGE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'GETRANGE';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               predis/src/Command/Redis/GEODIST.php                                                                0000644                 00000001016 15233650113 0013051 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/geodist
 */
class GEODIST extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'GEODIST';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/GEORADIUS.php                                                              0000644                 00000003746 15233650113 0013311 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @deprecated As of Redis version 6.2.0, this command is regarded as deprecated.
 *
 * It can be replaced by GEOSEARCH and GEOSEARCHSTORE with the BYRADIUS argument
 * when migrating or writing new code.
 *
 * @see http://redis.io/commands/georadius
 */
class GEORADIUS extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'GEORADIUS';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if ($arguments && is_array(end($arguments))) {
            $options = array_change_key_case(array_pop($arguments), CASE_UPPER);

            if (isset($options['WITHCOORD']) && $options['WITHCOORD'] == true) {
                $arguments[] = 'WITHCOORD';
            }

            if (isset($options['WITHDIST']) && $options['WITHDIST'] == true) {
                $arguments[] = 'WITHDIST';
            }

            if (isset($options['WITHHASH']) && $options['WITHHASH'] == true) {
                $arguments[] = 'WITHHASH';
            }

            if (isset($options['COUNT'])) {
                $arguments[] = 'COUNT';
                $arguments[] = $options['COUNT'];
            }

            if (isset($options['SORT'])) {
                $arguments[] = strtoupper($options['SORT']);
            }

            if (isset($options['STORE'])) {
                $arguments[] = 'STORE';
                $arguments[] = $options['STORE'];
            }

            if (isset($options['STOREDIST'])) {
                $arguments[] = 'STOREDIST';
                $arguments[] = $options['STOREDIST'];
            }
        }

        parent::setArguments($arguments);
    }
}
                          predis/src/Command/Redis/QUIT.php                                                                   0000644                 00000001005 15233650113 0012533 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/quit
 */
class QUIT extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'QUIT';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/PEXPIREAT.php                                                              0000644                 00000001024 15233650113 0013313 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/pexpireat
 */
class PEXPIREAT extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'PEXPIREAT';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            predis/src/Command/Redis/BLMPOP.php                                                                 0000644                 00000001053 15233650113 0012745 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

class BLMPOP extends LMPOP
{
    protected static $keysArgumentPositionOffset = 1;
    protected static $leftRightArgumentPositionOffset = 2;
    protected static $countArgumentPositionOffset = 3;

    public function getId()
    {
        return 'BLMPOP';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/ZRANGESTORE.php                                                            0000644                 00000002635 15233650113 0013566 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\By\ByLexByScore;
use Predis\Command\Traits\Limit\Limit;
use Predis\Command\Traits\Rev;

/**
 * @see https://redis.io/commands/zrangestore/
 *
 * This command is like ZRANGE, but stores the result in the destination key.
 */
class ZRANGESTORE extends RedisCommand
{
    use ByLexByScore {
        ByLexByScore::setArguments as setByLexByScoreArgument;
    }
    use Rev {
        Rev::setArguments as setReversedArgument;
    }
    use Limit {
        Limit::setArguments as setLimitArguments;
    }

    protected static $byLexByScoreArgumentPositionOffset = 4;
    protected static $revArgumentPositionOffset = 5;
    protected static $limitArgumentPositionOffset = 6;

    public function getId()
    {
        return 'ZRANGESTORE';
    }

    public function setArguments(array $arguments)
    {
        $this->setByLexByScoreArgument($arguments);
        $arguments = $this->getArguments();

        $this->setReversedArgument($arguments);
        $arguments = $this->getArguments();

        $this->setLimitArguments($arguments);
        $this->filterArguments();
    }
}
                                                                                                   predis/src/Command/Redis/SETRANGE.php                                                               0000644                 00000001021 15233650113 0013157 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/setrange
 */
class SETRANGE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SETRANGE';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               predis/src/Command/Redis/SSCAN.php                                                                  0000644                 00000002720 15233650113 0012625 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/sscan
 */
class SSCAN extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SSCAN';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 3 && is_array($arguments[2])) {
            $options = $this->prepareOptions(array_pop($arguments));
            $arguments = array_merge($arguments, $options);
        }

        parent::setArguments($arguments);
    }

    /**
     * Returns a list of options and modifiers compatible with Redis.
     *
     * @param array $options List of options.
     *
     * @return array
     */
    protected function prepareOptions($options)
    {
        $options = array_change_key_case($options, CASE_UPPER);
        $normalized = [];

        if (!empty($options['MATCH'])) {
            $normalized[] = 'MATCH';
            $normalized[] = $options['MATCH'];
        }

        if (!empty($options['COUNT'])) {
            $normalized[] = 'COUNT';
            $normalized[] = $options['COUNT'];
        }

        return $normalized;
    }
}
                                                predis/src/Command/Redis/ZUNIONSTORE.php                                                            0000644                 00000003233 15233650113 0013615 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Aggregate;
use Predis\Command\Traits\Keys;
use Predis\Command\Traits\Weights;

/**
 * @see http://redis.io/commands/zunionstore
 */
class ZUNIONSTORE extends RedisCommand
{
    use Keys {
        Keys::setArguments as setKeys;
    }
    use Weights {
        Weights::setArguments as setWeights;
    }
    use Aggregate{
        Aggregate::setArguments as setAggregate;
    }

    protected static $keysArgumentPositionOffset = 1;
    protected static $weightsArgumentPositionOffset = 2;
    protected static $aggregateArgumentPositionOffset = 3;

    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZUNIONSTORE';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        // support old `$options` array for backwards compatibility
        if (!isset($arguments[3]) && (isset($arguments[2]['weights']) || isset($arguments[2]['aggregate']))) {
            $options = array_pop($arguments);
            array_push($arguments, $options['weights'] ?? []);
            array_push($arguments, $options['aggregate'] ?? 'sum');
        }

        $this->setAggregate($arguments);
        $arguments = $this->getArguments();

        $this->setWeights($arguments);
        $arguments = $this->getArguments();

        $this->setKeys($arguments);
    }
}
                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/SUBSCRIBE.php                                                              0000644                 00000001337 15233650113 0013302 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/subscribe
 */
class SUBSCRIBE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SUBSCRIBE';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeArguments($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                 predis/src/Command/Redis/STRLEN.php                                                                 0000644                 00000001013 15233650113 0012757 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/strlen
 */
class STRLEN extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'STRLEN';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/ZRANGE.php                                                                 0000644                 00000004661 15233650113 0012752 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/zrange
 */
class ZRANGE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZRANGE';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 4) {
            $lastType = gettype($arguments[3]);

            if ($lastType === 'string' && strtoupper($arguments[3]) === 'WITHSCORES') {
                // Used for compatibility with older versions
                $arguments[3] = ['WITHSCORES' => true];
                $lastType = 'array';
            }

            if ($lastType === 'array') {
                $options = $this->prepareOptions(array_pop($arguments));
                $arguments = array_merge($arguments, $options);
            }
        }

        parent::setArguments($arguments);
    }

    /**
     * Returns a list of options and modifiers compatible with Redis.
     *
     * @param array $options List of options.
     *
     * @return array
     */
    protected function prepareOptions($options)
    {
        $opts = array_change_key_case($options, CASE_UPPER);
        $finalizedOpts = [];

        if (!empty($opts['WITHSCORES'])) {
            $finalizedOpts[] = 'WITHSCORES';
        }

        return $finalizedOpts;
    }

    /**
     * Checks for the presence of the WITHSCORES modifier.
     *
     * @return bool
     */
    protected function withScores()
    {
        $arguments = $this->getArguments();

        if (count($arguments) < 4) {
            return false;
        }

        return strtoupper($arguments[3]) === 'WITHSCORES';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        if ($this->withScores()) {
            $result = [];

            for ($i = 0; $i < count($data); ++$i) {
                if (is_array($data[$i])) {
                    $result[$data[$i][0]] = $data[$i][1]; // Relay
                } else {
                    $result[$data[$i]] = $data[++$i];
                }
            }

            return $result;
        }

        return $data;
    }
}
                                                                               predis/src/Command/Redis/PFMERGE.php                                                                0000644                 00000001331 15233650113 0013040 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/pfmerge
 */
class PFMERGE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'PFMERGE';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeArguments($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                       predis/src/Command/Redis/SDIFFSTORE.php                                                             0000644                 00000001471 15233650113 0013430 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/sdiffstore
 */
class SDIFFSTORE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SDIFFSTORE';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 2 && is_array($arguments[1])) {
            $arguments = array_merge([$arguments[0]], $arguments[1]);
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                       predis/src/Command/Redis/ZDIFF.php                                                                  0000644                 00000002052 15233650113 0012616 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Keys;
use Predis\Command\Traits\With\WithScores;

/**
 * @see https://redis.io/commands/zdiff/
 *
 * This command is similar to ZDIFFSTORE, but instead of
 * storing the resulting sorted set, it is returned to the client.
 */
class ZDIFF extends RedisCommand
{
    use WithScores {
        WithScores::setArguments as setWithScore;
    }
    use Keys {
        Keys::setArguments as setKeys;
    }

    protected static $keysArgumentPositionOffset = 0;

    public function getId()
    {
        return 'ZDIFF';
    }

    public function setArguments(array $arguments)
    {
        $this->setKeys($arguments);
        $arguments = $this->getArguments();

        $this->setWithScore($arguments);
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      predis/src/Command/Redis/XDEL.php                                                                   0000644                 00000001317 15233650113 0012513 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/xdel
 */
class XDEL extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'XDEL';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeVariadic($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                                 predis/src/Command/Redis/HINCRBY.php                                                                0000644                 00000001016 15233650113 0013051 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/hincrby
 */
class HINCRBY extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'HINCRBY';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/SMOVE.php                                                                  0000644                 00000001010 15233650113 0012636 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/smove
 */
class SMOVE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'SMOVE';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/CLUSTER.php                                                                0000644                 00000000760 15233650113 0013101 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/?name=cluster
 */
class CLUSTER extends RedisCommand
{
    public function getId()
    {
        return 'CLUSTER';
    }
}
                predis/src/Command/Redis/EVALSHA.php                                                                0000644                 00000001241 15233650113 0013036 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

/**
 * @see http://redis.io/commands/evalsha
 */
class EVALSHA extends EVAL_
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'EVALSHA';
    }

    /**
     * Returns the SHA1 hash of the body of the script.
     *
     * @return string SHA1 hash.
     */
    public function getScriptHash()
    {
        return $this->getArgument(0);
    }
}
                                                                                                                                                                                                                                                                                                                                                               predis/src/Command/Redis/GET.php                                                                    0000644                 00000001002 15233650113 0012365 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/get
 */
class GET extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'GET';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              predis/src/Command/Redis/BRPOP.php                                                                  0000644                 00000001503 15233650113 0012636 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/brpop
 */
class BRPOP extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'BRPOP';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (count($arguments) === 2 && is_array($arguments[0])) {
            [$arguments, $timeout] = $arguments;
            array_push($arguments, $timeout);
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                             predis/src/Command/Redis/LREM.php                                                                   0000644                 00000001005 15233650113 0012510 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/lrem
 */
class LREM extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'LREM';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Redis/PFADD.php                                                                  0000644                 00000001322 15233650113 0012571 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/pfadd
 */
class PFADD extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'PFADD';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeVariadic($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                              predis/src/Command/Redis/RPUSH.php                                                                  0000644                 00000001322 15233650113 0012654 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/rpush
 */
class RPUSH extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'RPUSH';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeVariadic($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                              predis/src/Command/Redis/APPEND.php                                                                 0000644                 00000001013 15233650113 0012717 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/append
 */
class APPEND extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'APPEND';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/FLUSHDB.php                                                                0000644                 00000001016 15233650113 0013042 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/flushdb
 */
class FLUSHDB extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'FLUSHDB';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/EVAL_.php                                                                  0000644                 00000001326 15233650113 0012645 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/eval
 */
class EVAL_ extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'EVAL';
    }

    /**
     * Calculates the SHA1 hash of the body of the script.
     *
     * @return string SHA1 hash.
     */
    public function getScriptHash()
    {
        return sha1($this->getArgument(0));
    }
}
                                                                                                                                                                                                                                                                                                          predis/src/Command/Redis/TopK/TOPKLIST.php                                                          0000644                 00000003034 15233650113 0014103 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TopK;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/topk.list/
 *
 * Return full list of items in Top K list.
 */
class TOPKLIST extends RedisCommand
{
    public function getId()
    {
        return 'TOPK.LIST';
    }

    public function setArguments(array $arguments)
    {
        if (!empty($arguments[1])) {
            $arguments[1] = 'WITHCOUNT';
        }

        parent::setArguments($arguments);
        $this->filterArguments();
    }

    public function parseResponse($data)
    {
        if ($this->isWithCountModifier()) {
            $result = [];

            for ($i = 0, $iMax = count($data); $i < $iMax; ++$i) {
                if (array_key_exists($i + 1, $data)) {
                    $result[(string) $data[$i]] = $data[++$i];
                }
            }

            return $result;
        }

        return $data;
    }

    /**
     * Checks for the presence of the WITHCOUNT modifier.
     *
     * @return bool
     */
    private function isWithCountModifier(): bool
    {
        $arguments = $this->getArguments();
        $lastArgument = (!empty($arguments)) ? $arguments[count($arguments) - 1] : null;

        return is_string($lastArgument) && strtoupper($lastArgument) === 'WITHCOUNT';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    predis/src/Command/Redis/TopK/TOPKADD.php                                                           0000644                 00000001363 15233650113 0013723 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TopK;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/topk.add/
 *
 * Adds an item to the data structure.
 * Multiple items can be added at once.
 * If an item enters the Top-K list, the item which is expelled is returned.
 * This allows dynamic heavy-hitter detection of items being entered or expelled from Top-K list.
 */
class TOPKADD extends RedisCommand
{
    public function getId()
    {
        return 'TOPK.ADD';
    }
}
                                                                                                                                                                                                                                                                             predis/src/Command/Redis/TopK/TOPKQUERY.php                                                         0000644                 00000001126 15233650113 0014235 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TopK;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/topk.query/
 *
 * Checks whether an item is one of Top-K items.
 * Multiple items can be checked at once.
 */
class TOPKQUERY extends RedisCommand
{
    public function getId()
    {
        return 'TOPK.QUERY';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                          predis/src/Command/Redis/TopK/TOPKINFO.php                                                          0000644                 00000001553 15233650113 0014067 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TopK;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/topk.info/
 *
 * Returns number of required items (k), width, depth and decay values.
 */
class TOPKINFO extends RedisCommand
{
    public function getId()
    {
        return 'TOPK.INFO';
    }

    public function parseResponse($data)
    {
        $result = [];

        for ($i = 0, $iMax = count($data); $i < $iMax; ++$i) {
            if (array_key_exists($i + 1, $data)) {
                $result[(string) $data[$i]] = $data[++$i];
            }
        }

        return $result;
    }
}
                                                                                                                                                     predis/src/Command/Redis/TopK/TOPKINCRBY.php                                                        0000644                 00000001303 15233650113 0014313 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TopK;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/topk.incrby/
 *
 * Increase the score of an item in the data structure by increment.
 * Multiple items' score can be increased at once.
 * If an item enters the Top-K list, the item which is expelled is returned.
 */
class TOPKINCRBY extends RedisCommand
{
    public function getId()
    {
        return 'TOPK.INCRBY';
    }
}
                                                                                                                                                                                                                                                                                                                             predis/src/Command/Redis/TopK/TOPKRESERVE.php                                                       0000644                 00000002037 15233650113 0014445 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TopK;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/topk.reserve/
 *
 * Initializes a TopK with specified parameters.
 */
class TOPKRESERVE extends RedisCommand
{
    public function getId()
    {
        return 'TOPK.RESERVE';
    }

    public function setArguments(array $arguments)
    {
        switch (count($arguments)) {
            case 3:
                $arguments[] = 7; // default depth
                $arguments[] = 0.9; // default decay
                break;
            case 4:
                $arguments[] = 0.9; // default decay
                break;
            default:
                parent::setArguments($arguments);

                return;
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 predis/src/Command/Redis/EVALSHA_RO.php                                                             0000644                 00000001055 15233650113 0013441 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

/**
 * @see https://redis.io/commands/evalsha_ro/
 *
 * This is a read-only variant of the EVALSHA command
 * that cannot execute commands that modify data.
 */
class EVALSHA_RO extends EVAL_RO
{
    public function getId()
    {
        return 'EVALSHA_RO';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   predis/src/Command/Redis/UNWATCH.php                                                                0000644                 00000001016 15233650113 0013064 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/unwatch
 */
class UNWATCH extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'UNWATCH';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/RPUSHX.php                                                                 0000644                 00000001013 15233650113 0013001 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/rpushx
 */
class RPUSHX extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'RPUSHX';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/GEOSEARCH.php                                                              0000644                 00000006520 15233650113 0013260 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\By\GeoBy;
use Predis\Command\Traits\Count;
use Predis\Command\Traits\From\GeoFrom;
use Predis\Command\Traits\Sorting;
use Predis\Command\Traits\With\WithCoord;
use Predis\Command\Traits\With\WithDist;
use Predis\Command\Traits\With\WithHash;

/**
 * @see https://redis.io/commands/geosearch/
 *
 * Return the members of a sorted set populated with geospatial information using GEOADD,
 * which are within the borders of the area specified by a given shape.
 *
 * This command extends the GEORADIUS command, so in addition to searching
 * within circular areas, it supports searching within rectangular areas.
 */
class GEOSEARCH extends RedisCommand
{
    use GeoFrom {
        GeoFrom::setArguments as setFrom;
    }
    use GeoBy {
        GeoBy::setArguments as setBy;
    }
    use Sorting {
        Sorting::setArguments as setSorting;
    }
    use Count {
        Count::setArguments as setCount;
    }
    use WithCoord {
        WithCoord::setArguments as setWithCoord;
    }
    use WithDist {
        WithDist::setArguments as setWithDist;
    }
    use WithHash {
        WithHash::setArguments as setWithHash;
    }

    protected static $sortArgumentPositionOffset = 3;
    protected static $countArgumentPositionOffset = 4;
    protected static $withCoordArgumentPositionOffset = 6;
    protected static $withDistArgumentPositionOffset = 7;
    protected static $withHashArgumentPositionOffset = 8;

    public function getId()
    {
        return 'GEOSEARCH';
    }

    public function setArguments(array $arguments)
    {
        $this->setSorting($arguments);
        $arguments = $this->getArguments();

        $this->setWithCoord($arguments);
        $arguments = $this->getArguments();

        $this->setWithDist($arguments);
        $arguments = $this->getArguments();

        $this->setWithHash($arguments);
        $arguments = $this->getArguments();

        $this->setCount($arguments, $arguments[5] ?? false);
        $arguments = $this->getArguments();

        $this->setFrom($arguments);
        $arguments = $this->getArguments();

        $this->setBy($arguments);
        $this->filterArguments();
    }

    public function parseResponse($data)
    {
        $parsedData = [];
        $itemKey = '';

        foreach ($data as $item) {
            if (!is_array($item)) {
                $parsedData[] = $item;
                continue;
            }

            foreach ($item as $key => $itemRow) {
                if ($key === 0) {
                    $itemKey = $itemRow;
                    continue;
                }

                if (is_string($itemRow)) {
                    $parsedData[$itemKey]['dist'] = round((float) $itemRow, 5);
                } elseif (is_int($itemRow)) {
                    $parsedData[$itemKey]['hash'] = $itemRow;
                } else {
                    $parsedData[$itemKey]['lng'] = round($itemRow[0], 5);
                    $parsedData[$itemKey]['lat'] = round($itemRow[1], 5);
                }
            }
        }

        return $parsedData;
    }
}
                                                                                                                                                                                predis/src/Command/Redis/INFO.php                                                                   0000644                 00000006442 15233650113 0012516 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/info
 */
class INFO extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'INFO';
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        if (empty($data) || !$lines = preg_split('/\r?\n/', $data)) {
            return [];
        }

        if (strpos($lines[0], '#') === 0) {
            return $this->parseNewResponseFormat($lines);
        } else {
            return $this->parseOldResponseFormat($lines);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function parseNewResponseFormat($lines)
    {
        $info = [];
        $current = null;

        foreach ($lines as $row) {
            if ($row === '') {
                continue;
            }

            if (preg_match('/^# (\w+)$/', $row, $matches)) {
                $info[$matches[1]] = [];
                $current = &$info[$matches[1]];
                continue;
            }

            [$k, $v] = $this->parseRow($row);
            $current[$k] = $v;
        }

        return $info;
    }

    /**
     * {@inheritdoc}
     */
    public function parseOldResponseFormat($lines)
    {
        $info = [];

        foreach ($lines as $row) {
            if (strpos($row, ':') === false) {
                continue;
            }

            [$k, $v] = $this->parseRow($row);
            $info[$k] = $v;
        }

        return $info;
    }

    /**
     * Parses a single row of the response and returns the key-value pair.
     *
     * @param string $row Single row of the response.
     *
     * @return array
     */
    protected function parseRow($row)
    {
        if (preg_match('/^module:name/', $row)) {
            return $this->parseModuleRow($row);
        }

        [$k, $v] = explode(':', $row, 2);

        if (preg_match('/^db\d+$/', $k)) {
            $v = $this->parseDatabaseStats($v);
        }

        return [$k, $v];
    }

    /**
     * Extracts the statistics of each logical DB from the string buffer.
     *
     * @param string $str Response buffer.
     *
     * @return array
     */
    protected function parseDatabaseStats($str)
    {
        $db = [];

        foreach (explode(',', $str) as $dbvar) {
            [$dbvk, $dbvv] = explode('=', $dbvar);
            $db[trim($dbvk)] = $dbvv;
        }

        return $db;
    }

    /**
     * Parsing module rows because of different format.
     *
     * @param  string $row
     * @return array
     */
    protected function parseModuleRow(string $row): array
    {
        [$moduleKeyword, $moduleData] = explode(':', $row);
        $explodedData = explode(',', $moduleData);
        $parsedData = [];

        foreach ($explodedData as $moduleDataRow) {
            [$k, $v] = explode('=', $moduleDataRow);

            if ($k === 'name') {
                $parsedData[0] = $v;
                continue;
            }

            $parsedData[1][$k] = $v;
        }

        return $parsedData;
    }
}
                                                                                                                                                                                                                              predis/src/Command/Redis/ZREM.php                                                                   0000644                 00000001317 15233650113 0012534 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/zrem
 */
class ZREM extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZREM';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $arguments = self::normalizeVariadic($arguments);

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                                 predis/src/Command/Redis/TimeSeries/TSMGET.php                                                      0000644                 00000001512 15233650113 0015030 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TimeSeries;

use Predis\Command\Command as RedisCommand;

class TSMGET extends RedisCommand
{
    public function getId()
    {
        return 'TS.MGET';
    }

    public function setArguments(array $arguments)
    {
        $processedArguments = [];
        $argumentsObject = array_shift($arguments);
        $commandArguments = $argumentsObject->toArray();

        array_push($processedArguments, 'FILTER', ...$arguments);

        parent::setArguments(array_merge(
            $commandArguments,
            $processedArguments
        ));
    }
}
                                                                                                                                                                                      predis/src/Command/Redis/TimeSeries/TSINCRBY.php                                                    0000644                 00000001770 15233650113 0015270 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TimeSeries;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ts.incrby/
 *
 * Increase the value of the sample with the maximum existing timestamp,
 * or create a new sample with a value equal to the value of the sample
 * with the maximum existing timestamp with a given increment
 */
class TSINCRBY extends RedisCommand
{
    public function getId()
    {
        return 'TS.INCRBY';
    }

    public function setArguments(array $arguments)
    {
        [$key, $value] = $arguments;
        $commandArguments = (!empty($arguments[2])) ? $arguments[2]->toArray() : [];

        parent::setArguments(array_merge(
            [$key, $value],
            $commandArguments
        ));
    }
}
        predis/src/Command/Redis/TimeSeries/TSMRANGE.php                                                    0000644                 00000001570 15233650113 0015251 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TimeSeries;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ts.mrange/
 *
 * Query a range across multiple time series by filters in forward direction.
 */
class TSMRANGE extends RedisCommand
{
    public function getId()
    {
        return 'TS.MRANGE';
    }

    public function setArguments(array $arguments)
    {
        [$fromTimestamp, $toTimestamp] = $arguments;
        $commandArguments = $arguments[2]->toArray();

        parent::setArguments(array_merge(
            [$fromTimestamp, $toTimestamp],
            $commandArguments
        ));
    }
}
                                                                                                                                        predis/src/Command/Redis/TimeSeries/TSADD.php                                                       0000644                 00000001535 15233650113 0014671 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TimeSeries;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ts.add/
 *
 * Append a sample to a time series.
 */
class TSADD extends RedisCommand
{
    public function getId()
    {
        return 'TS.ADD';
    }

    public function setArguments(array $arguments)
    {
        [$key, $timestamp, $value] = $arguments;
        $commandArguments = (!empty($arguments[3])) ? $arguments[3]->toArray() : [];

        parent::setArguments(array_merge(
            [$key, $timestamp, $value],
            $commandArguments
        ));
    }
}
                                                                                                                                                                   predis/src/Command/Redis/TimeSeries/TSMADD.php                                                      0000644                 00000001052 15233650113 0015000 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TimeSeries;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ts.madd/
 *
 * Append new samples to one or more time series.
 */
class TSMADD extends RedisCommand
{
    public function getId()
    {
        return 'TS.MADD';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      predis/src/Command/Redis/TimeSeries/TSDELETERULE.php                                                0000644                 00000001047 15233650113 0015731 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TimeSeries;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ts.deleterule/
 *
 * Delete a compaction rule.
 */
class TSDELETERULE extends RedisCommand
{
    public function getId()
    {
        return 'TS.DELETERULE';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         predis/src/Command/Redis/TimeSeries/TSCREATE.php                                                    0000644                 00000001466 15233650113 0015247 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TimeSeries;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ts.create/
 *
 * Create a new time series.
 */
class TSCREATE extends RedisCommand
{
    public function getId()
    {
        return 'TS.CREATE';
    }

    public function setArguments(array $arguments)
    {
        [$key] = $arguments;
        $commandArguments = (!empty($arguments[1])) ? $arguments[1]->toArray() : [];

        parent::setArguments(array_merge(
            [$key],
            $commandArguments
        ));
    }
}
                                                                                                                                                                                                          predis/src/Command/Redis/TimeSeries/TSCREATERULE.php                                                0000644                 00000001655 15233650113 0015737 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TimeSeries;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ts.createrule/
 *
 * Create a compaction rule
 */
class TSCREATERULE extends RedisCommand
{
    public function getId()
    {
        return 'TS.CREATERULE';
    }

    public function setArguments(array $arguments)
    {
        [$sourceKey, $destKey, $aggregator, $bucketDuration] = $arguments;
        $processedArguments = [$sourceKey, $destKey, 'AGGREGATION', $aggregator, $bucketDuration];

        if (count($arguments) === 5) {
            $processedArguments[] = $arguments[4];
        }

        parent::setArguments($processedArguments);
    }
}
                                                                                   predis/src/Command/Redis/TimeSeries/TSDECRBY.php                                                    0000644                 00000001771 15233650113 0015253 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TimeSeries;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ts.decrby/
 *
 * Decrease the value of the sample with the maximum existing timestamp,
 * or create a new sample with a value equal to the value of the sample
 * with the maximum existing timestamp with a given decrement.
 */
class TSDECRBY extends RedisCommand
{
    public function getId()
    {
        return 'TS.DECRBY';
    }

    public function setArguments(array $arguments)
    {
        [$key, $value] = $arguments;
        $commandArguments = (!empty($arguments[2])) ? $arguments[2]->toArray() : [];

        parent::setArguments(array_merge(
            [$key, $value],
            $commandArguments
        ));
    }
}
       predis/src/Command/Redis/TimeSeries/TSMREVRANGE.php                                                 0000644                 00000001044 15233650113 0015622 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TimeSeries;

/**
 * @see https://redis.io/commands/ts.mrevrange/
 *
 * Query a range across multiple time series by filters in reverse direction.
 */
class TSMREVRANGE extends TSMRANGE
{
    public function getId()
    {
        return 'TS.MREVRANGE';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            predis/src/Command/Redis/TimeSeries/TSDEL.php                                                       0000644                 00000001073 15233650113 0014702 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TimeSeries;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ts.del/
 *
 * Delete all samples between two timestamps for a given time series.
 */
class TSDEL extends RedisCommand
{
    public function getId()
    {
        return 'TS.DEL';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Redis/TimeSeries/TSREVRANGE.php                                                  0000644                 00000000771 15233650113 0015513 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TimeSeries;

/**
 * @see https://redis.io/commands/ts.revrange/
 *
 * Query a range in reverse direction.
 */
class TSREVRANGE extends TSRANGE
{
    public function getId()
    {
        return 'TS.REVRANGE';
    }
}
       predis/src/Command/Redis/TimeSeries/TSRANGE.php                                                     0000644                 00000001571 15233650113 0015135 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TimeSeries;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ts.range/
 *
 * Query a range in forward direction.
 */
class TSRANGE extends RedisCommand
{
    public function getId()
    {
        return 'TS.RANGE';
    }

    public function setArguments(array $arguments)
    {
        [$key, $fromTimestamp, $toTimestamp] = $arguments;
        $commandArguments = (!empty($arguments[3])) ? $arguments[3]->toArray() : [];

        parent::setArguments(array_merge(
            [$key, $fromTimestamp, $toTimestamp],
            $commandArguments
        ));
    }
}
                                                                                                                                       predis/src/Command/Redis/TimeSeries/TSINFO.php                                                      0000644                 00000001513 15233650113 0015030 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TimeSeries;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ts.info/
 *
 * Return information and statistics for a time series.
 */
class TSINFO extends RedisCommand
{
    public function getId()
    {
        return 'TS.INFO';
    }

    public function setArguments(array $arguments)
    {
        [$key] = $arguments;
        $commandArguments = (!empty($arguments[1])) ? $arguments[1]->toArray() : [];

        parent::setArguments(array_merge(
            [$key],
            $commandArguments
        ));
    }
}
                                                                                                                                                                                     predis/src/Command/Redis/TimeSeries/TSQUERYINDEX.php                                                0000644                 00000001076 15233650113 0015776 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TimeSeries;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ts.queryindex/
 *
 * Get all time series keys matching a filter list.
 */
class TSQUERYINDEX extends RedisCommand
{
    public function getId()
    {
        return 'TS.QUERYINDEX';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Redis/TimeSeries/TSGET.php                                                       0000644                 00000001527 15233650113 0014721 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TimeSeries;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ts.get/
 *
 * Get the sample with the highest timestamp from a given time series.
 */
class TSGET extends RedisCommand
{
    public function getId()
    {
        return 'TS.GET';
    }

    public function setArguments(array $arguments)
    {
        [$key] = $arguments;
        $commandArguments = (!empty($arguments[1])) ? $arguments[1]->toArray() : [];

        parent::setArguments(array_merge(
            [$key],
            $commandArguments
        ));
    }
}
                                                                                                                                                                         predis/src/Command/Redis/TimeSeries/TSALTER.php                                                     0000644                 00000001564 15233650113 0015152 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis\TimeSeries;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/ts.alter/
 *
 * Update the retention, chunk size, duplicate policy, and labels of an existing time series.
 */
class TSALTER extends RedisCommand
{
    public function getId()
    {
        return 'TS.ALTER';
    }

    public function setArguments(array $arguments)
    {
        [$key] = $arguments;
        $commandArguments = (!empty($arguments[1])) ? $arguments[1]->toArray() : [];

        parent::setArguments(array_merge(
            [$key],
            $commandArguments
        ));
    }
}
                                                                                                                                            predis/src/Command/Redis/LTRIM.php                                                                  0000644                 00000001010 15233650113 0012634 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/ltrim
 */
class LTRIM extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'LTRIM';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/ZREMRANGEBYRANK.php                                                        0000644                 00000001046 15233650113 0014217 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/zremrangebyrank
 */
class ZREMRANGEBYRANK extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZREMRANGEBYRANK';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          predis/src/Command/Redis/PEXPIRETIME.php                                                            0000644                 00000001210 15233650113 0013542 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see https://redis.io/commands/pexpiretime/
 *
 * PEXPIRETIME has the same semantic as EXPIRETIME,
 * but returns the absolute Unix expiration timestamp in milliseconds instead of seconds.
 */
class PEXPIRETIME extends RedisCommand
{
    public function getId()
    {
        return 'PEXPIRETIME';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/ZREMRANGEBYSCORE.php                                                       0000644                 00000001051 15233650113 0014333 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/zremrangebyscore
 */
class ZREMRANGEBYSCORE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'ZREMRANGEBYSCORE';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       predis/src/Command/Redis/MIGRATE.php                                                                0000644                 00000002130 15233650113 0013041 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;

/**
 * @see http://redis.io/commands/migrate
 */
class MIGRATE extends RedisCommand
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'MIGRATE';
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (is_array(end($arguments))) {
            foreach (array_pop($arguments) as $modifier => $value) {
                $modifier = strtoupper($modifier);

                if ($modifier === 'COPY' && $value == true) {
                    $arguments[] = $modifier;
                }

                if ($modifier === 'REPLACE' && $value == true) {
                    $arguments[] = $modifier;
                }
            }
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/Redis/FCALL.php                                                                  0000644                 00000001144 15233650113 0012576 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Redis;

use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Keys;

/**
 * @see https://redis.io/commands/fcall/
 *
 * Invoke a function.
 */
class FCALL extends RedisCommand
{
    use Keys;

    protected static $keysArgumentPositionOffset = 1;

    public function getId()
    {
        return 'FCALL';
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                            predis/src/Command/RawFactory.php                                                                   0000644                 00000002124 15233650113 0012767 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command;

/**
 * Command factory creating raw command instances out of command IDs.
 *
 * Any command ID will produce a command instance even for unknown commands that
 * are not implemented by Redis (the server will return a "-ERR unknown command"
 * error responses).
 *
 * When using this factory the client does not process arguments before sending
 * commands to Redis and server responses are not further processed before being
 * returned to the caller.
 */
class RawFactory implements FactoryInterface
{
    /**
     * {@inheritdoc}
     */
    public function supports(string ...$commandIDs): bool
    {
        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function create(string $commandID, array $arguments = []): CommandInterface
    {
        return new RawCommand($commandID, $arguments);
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                            predis/src/Command/ScriptCommand.php                                                                0000644                 00000004610 15233650113 0013453 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command;

/**
 * Base class used to implement an higher level abstraction for commands based
 * on Lua scripting with EVAL and EVALSHA.
 *
 * @see http://redis.io/commands/eval
 */
abstract class ScriptCommand extends Command
{
    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return 'EVALSHA';
    }

    /**
     * Gets the body of a Lua script.
     *
     * @return string
     */
    abstract public function getScript();

    /**
     * Calculates the SHA1 hash of the body of the script.
     *
     * @return string SHA1 hash.
     */
    public function getScriptHash()
    {
        return sha1($this->getScript());
    }

    /**
     * Specifies the number of arguments that should be considered as keys.
     *
     * The default behaviour for the base class is to return 0 to indicate that
     * all the elements of the arguments array should be considered as keys, but
     * subclasses can enforce a static number of keys.
     *
     * @return int
     */
    protected function getKeysCount()
    {
        return 0;
    }

    /**
     * Returns the elements from the arguments that are identified as keys.
     *
     * @return array
     */
    public function getKeys()
    {
        return array_slice($this->getArguments(), 2, $this->getKeysCount());
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        if (($numkeys = $this->getKeysCount()) && $numkeys < 0) {
            $numkeys = count($arguments) + $numkeys;
        }

        $arguments = array_merge([$this->getScriptHash(), (int) $numkeys], $arguments);

        parent::setArguments($arguments);
    }

    /**
     * Returns arguments for EVAL command.
     *
     * @return array
     */
    public function getEvalArguments()
    {
        $arguments = $this->getArguments();
        $arguments[0] = $this->getScript();

        return $arguments;
    }

    /**
     * Returns the equivalent EVAL command as a raw command instance.
     *
     * @return RawCommand
     */
    public function getEvalCommand()
    {
        return new RawCommand('EVAL', $this->getEvalArguments());
    }
}
                                                                                                                        predis/src/Command/PrefixableCommandInterface.php                                                   0000644                 00000001130 15233650113 0016103 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command;

/**
 * Defines a command whose keys can be prefixed.
 */
interface PrefixableCommandInterface extends CommandInterface
{
    /**
     * Prefixes all the keys found in the arguments of the command.
     *
     * @param string $prefix String used to prefix the keys.
     */
    public function prefixKeys($prefix);
}
                                                                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Command/RawCommand.php                                                                   0000644                 00000005142 15233650113 0012741 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command;

/**
 * Class representing a generic Redis command.
 *
 * Arguments and responses for these commands are not normalized and they follow
 * what is defined by the Redis documentation.
 *
 * Raw commands can be useful when implementing higher level abstractions on top
 * of Predis\Client or managing internals like Redis Sentinel or Cluster as they
 * are not potentially subject to hijacking from third party libraries when they
 * override command handlers for standard Redis commands.
 */
final class RawCommand implements CommandInterface
{
    private $slot;
    private $commandID;
    private $arguments;

    /**
     * @param string $commandID Command ID
     * @param array  $arguments Command arguments
     */
    public function __construct($commandID, array $arguments = [])
    {
        $this->commandID = strtoupper($commandID);
        $this->setArguments($arguments);
    }

    /**
     * Creates a new raw command using a variadic method.
     *
     * @param string $commandID Redis command ID
     * @param string ...$args   Arguments list for the command
     *
     * @return CommandInterface
     */
    public static function create($commandID, ...$args)
    {
        $arguments = func_get_args();

        return new static(array_shift($arguments), $arguments);
    }

    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return $this->commandID;
    }

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $this->arguments = $arguments;
        unset($this->slot);
    }

    /**
     * {@inheritdoc}
     */
    public function setRawArguments(array $arguments)
    {
        $this->setArguments($arguments);
    }

    /**
     * {@inheritdoc}
     */
    public function getArguments()
    {
        return $this->arguments;
    }

    /**
     * {@inheritdoc}
     */
    public function getArgument($index)
    {
        if (isset($this->arguments[$index])) {
            return $this->arguments[$index];
        }
    }

    /**
     * {@inheritdoc}
     */
    public function setSlot($slot)
    {
        $this->slot = $slot;
    }

    /**
     * {@inheritdoc}
     */
    public function getSlot()
    {
        return $this->slot ?? null;
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        return $data;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                              predis/src/Command/Command.php                                                                      0000644                 00000005006 15233650113 0012266 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command;

/**
 * Base class for Redis commands.
 */
abstract class Command implements CommandInterface
{
    private $slot;
    private $arguments = [];

    /**
     * {@inheritdoc}
     */
    public function setArguments(array $arguments)
    {
        $this->arguments = $arguments;
        unset($this->slot);
    }

    /**
     * {@inheritdoc}
     */
    public function setRawArguments(array $arguments)
    {
        $this->arguments = $arguments;
        unset($this->slot);
    }

    /**
     * {@inheritdoc}
     */
    public function getArguments()
    {
        return $this->arguments;
    }

    /**
     * {@inheritdoc}
     */
    public function getArgument($index)
    {
        if (isset($this->arguments[$index])) {
            return $this->arguments[$index];
        }
    }

    /**
     * {@inheritdoc}
     */
    public function setSlot($slot)
    {
        $this->slot = $slot;
    }

    /**
     * {@inheritdoc}
     */
    public function getSlot()
    {
        return $this->slot ?? null;
    }

    /**
     * {@inheritdoc}
     */
    public function parseResponse($data)
    {
        return $data;
    }

    /**
     * Normalizes the arguments array passed to a Redis command.
     *
     * @param array $arguments Arguments for a command.
     *
     * @return array
     */
    public static function normalizeArguments(array $arguments)
    {
        if (count($arguments) === 1 && isset($arguments[0]) && is_array($arguments[0])) {
            return $arguments[0];
        }

        return $arguments;
    }

    /**
     * Normalizes the arguments array passed to a variadic Redis command.
     *
     * @param array $arguments Arguments for a command.
     *
     * @return array
     */
    public static function normalizeVariadic(array $arguments)
    {
        if (count($arguments) === 2 && is_array($arguments[1])) {
            return array_merge([$arguments[0]], $arguments[1]);
        }

        return $arguments;
    }

    /**
     * Remove all false values from arguments.
     *
     * @return void
     */
    public function filterArguments(): void
    {
        $this->arguments = array_filter($this->arguments, static function ($argument) {
            return $argument !== false && $argument !== null;
        });
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          predis/src/Command/RedisFactory.php                                                                 0000644                 00000006500 15233650113 0013306 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command;

use Predis\ClientConfiguration;
use Predis\Command\Redis\FUNCTIONS;

/**
 * Command factory for mainline Redis servers.
 *
 * This factory is intended to handle standard commands implemented by mainline
 * Redis servers. By default it maps a command ID to a specific command handler
 * class in the Predis\Command\Redis namespace but this can be overridden for
 * any command ID simply by defining a new command handler class implementing
 * Predis\Command\CommandInterface.
 */
class RedisFactory extends Factory
{
    private const COMMANDS_NAMESPACE = "Predis\Command\Redis";

    public function __construct()
    {
        $this->commands = [
            'ECHO' => 'Predis\Command\Redis\ECHO_',
            'EVAL' => 'Predis\Command\Redis\EVAL_',
            'OBJECT' => 'Predis\Command\Redis\OBJECT_',
            // Class name corresponds to PHP reserved word "function", added mapping to bypass restrictions
            'FUNCTION' => FUNCTIONS::class,
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function getCommandClass(string $commandID): ?string
    {
        $commandID = strtoupper($commandID);

        if (isset($this->commands[$commandID]) || array_key_exists($commandID, $this->commands)) {
            return $this->commands[$commandID];
        }

        $commandClass = $this->resolve($commandID);

        if (null === $commandClass) {
            return null;
        }

        $this->commands[$commandID] = $commandClass;

        return $commandClass;
    }

    /**
     * {@inheritdoc}
     */
    public function undefine(string $commandID): void
    {
        // NOTE: we explicitly associate `NULL` to the command ID in the map
        // instead of the parent's `unset()` because our subclass tries to load
        // a predefined class from the Predis\Command\Redis namespace when no
        // explicit mapping is defined, see RedisFactory::getCommandClass() for
        // details of the implementation of this mechanism.
        $this->commands[strtoupper($commandID)] = null;
    }

    /**
     * Resolves command object from given command ID.
     *
     * @param  string      $commandID Command ID of virtual method call
     * @return string|null FQDN of corresponding command object
     */
    private function resolve(string $commandID): ?string
    {
        if (class_exists($commandClass = self::COMMANDS_NAMESPACE . '\\' . $commandID)) {
            return $commandClass;
        }

        $commandModule = $this->resolveCommandModuleByPrefix($commandID);

        if (null === $commandModule) {
            return null;
        }

        if (class_exists($commandClass = self::COMMANDS_NAMESPACE . '\\' . $commandModule . '\\' . $commandID)) {
            return $commandClass;
        }

        return null;
    }

    private function resolveCommandModuleByPrefix(string $commandID): ?string
    {
        foreach (ClientConfiguration::getModules() as $module) {
            if (preg_match("/^{$module['commandPrefix']}/", $commandID)) {
                return $module['name'];
            }
        }

        return null;
    }
}
                                                                                                                                                                                                predis/src/Command/Strategy/StrategyResolverInterface.php                                           0000644                 00000001206 15233650113 0017655 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Strategy;

interface StrategyResolverInterface
{
    /**
     * Resolves subcommand strategy.
     *
     * @param  string                      $commandId
     * @param  string                      $subcommandId
     * @return SubcommandStrategyInterface
     */
    public function resolve(string $commandId, string $subcommandId): SubcommandStrategyInterface;
}
                                                                                                                                                                                                                                                                                                                                                                                          predis/src/Command/Strategy/SubcommandStrategyInterface.php                                         0000644                 00000001011 15233650113 0020136 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Strategy;

interface SubcommandStrategyInterface
{
    /**
     * Process arguments for given subcommand.
     *
     * @param  array $arguments
     * @return array
     */
    public function processArguments(array $arguments): array;
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       predis/src/Command/Strategy/ContainerCommands/Functions/LoadStrategy.php                            0000644                 00000001743 15233650113 0022474 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Strategy\ContainerCommands\Functions;

use Predis\Command\Strategy\SubcommandStrategyInterface;

class LoadStrategy implements SubcommandStrategyInterface
{
    /**
     * {@inheritdoc}
     */
    public function processArguments(array $arguments): array
    {
        if (count($arguments) <= 2) {
            return $arguments;
        }

        $processedArguments = [$arguments[0]];
        $replace = array_pop($arguments);

        if (is_bool($replace) && $replace) {
            $processedArguments[] = 'REPLACE';
        } elseif (!is_bool($replace)) {
            $processedArguments[] = $replace;
        }

        $processedArguments[] = $arguments[1];

        return $processedArguments;
    }
}
                             predis/src/Command/Strategy/ContainerCommands/Functions/FlushStrategy.php                           0000644                 00000001420 15233650113 0022666 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Strategy\ContainerCommands\Functions;

use Predis\Command\Strategy\SubcommandStrategyInterface;

class FlushStrategy implements SubcommandStrategyInterface
{
    /**
     * {@inheritDoc}
     */
    public function processArguments(array $arguments): array
    {
        $processedArguments = [$arguments[0]];

        if (array_key_exists(1, $arguments) && null !== $arguments[1]) {
            $processedArguments[] = strtoupper($arguments[1]);
        }

        return $processedArguments;
    }
}
                                                                                                                                                                                                                                                predis/src/Command/Strategy/ContainerCommands/Functions/DeleteStrategy.php                          0000644                 00000001105 15233650113 0023007 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Strategy\ContainerCommands\Functions;

use Predis\Command\Strategy\SubcommandStrategyInterface;

class DeleteStrategy implements SubcommandStrategyInterface
{
    /**
     * {@inheritDoc}
     */
    public function processArguments(array $arguments): array
    {
        return $arguments;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Strategy/ContainerCommands/Functions/DumpStrategy.php                            0000644                 00000001103 15233650113 0022510 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Strategy\ContainerCommands\Functions;

use Predis\Command\Strategy\SubcommandStrategyInterface;

class DumpStrategy implements SubcommandStrategyInterface
{
    /**
     * {@inheritDoc}
     */
    public function processArguments(array $arguments): array
    {
        return $arguments;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                             predis/src/Command/Strategy/ContainerCommands/Functions/KillStrategy.php                            0000644                 00000001103 15233650113 0022476 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Strategy\ContainerCommands\Functions;

use Predis\Command\Strategy\SubcommandStrategyInterface;

class KillStrategy implements SubcommandStrategyInterface
{
    /**
     * {@inheritDoc}
     */
    public function processArguments(array $arguments): array
    {
        return $arguments;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                             predis/src/Command/Strategy/ContainerCommands/Functions/StatsStrategy.php                           0000644                 00000001104 15233650113 0022702 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Strategy\ContainerCommands\Functions;

use Predis\Command\Strategy\SubcommandStrategyInterface;

class StatsStrategy implements SubcommandStrategyInterface
{
    /**
     * {@inheritDoc}
     */
    public function processArguments(array $arguments): array
    {
        return $arguments;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                            predis/src/Command/Strategy/ContainerCommands/Functions/ListStrategy.php                            0000644                 00000001637 15233650113 0022532 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Strategy\ContainerCommands\Functions;

use Predis\Command\Strategy\SubcommandStrategyInterface;

class ListStrategy implements SubcommandStrategyInterface
{
    /**
     * {@inheritDoc}
     */
    public function processArguments(array $arguments): array
    {
        $processedArguments = [$arguments[0]];

        if (array_key_exists(1, $arguments) && null !== $arguments[1]) {
            array_push($processedArguments, 'LIBRARYNAME', $arguments[1]);
        }

        if (array_key_exists(2, $arguments) && true === $arguments[2]) {
            $processedArguments[] = 'WITHCODE';
        }

        return $processedArguments;
    }
}
                                                                                                 predis/src/Command/Strategy/ContainerCommands/Functions/RestoreStrategy.php                         0000644                 00000001441 15233650113 0023233 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Strategy\ContainerCommands\Functions;

use Predis\Command\Strategy\SubcommandStrategyInterface;

class RestoreStrategy implements SubcommandStrategyInterface
{
    /**
     * {@inheritDoc}
     */
    public function processArguments(array $arguments): array
    {
        $processedArguments = [$arguments[0], $arguments[1]];

        if (array_key_exists(2, $arguments) && null !== $arguments[2]) {
            $processedArguments[] = strtoupper($arguments[2]);
        }

        return $processedArguments;
    }
}
                                                                                                                                                                                                                               predis/src/Command/Strategy/SubcommandStrategyResolver.php                                          0000644                 00000002740 15233650113 0020051 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Strategy;

use InvalidArgumentException;

class SubcommandStrategyResolver implements StrategyResolverInterface
{
    private const CONTAINER_COMMANDS_NAMESPACE = 'Predis\Command\Strategy\ContainerCommands';

    /**
     * @var ?string
     */
    private $separator;

    public function __construct(string $separator = null)
    {
        $this->separator = $separator;
    }

    /**
     * {@inheritDoc}
     */
    public function resolve(string $commandId, string $subcommandId): SubcommandStrategyInterface
    {
        $subcommandStrategyClass = ucwords($subcommandId) . 'Strategy';
        $commandDirectoryName = ucwords($commandId);

        if (!is_null($this->separator)) {
            $subcommandStrategyClass = str_replace($this->separator, '', $subcommandStrategyClass);
            $commandDirectoryName = str_replace($this->separator, '', $commandDirectoryName);
        }

        if (class_exists(
            $containerCommandClass = self::CONTAINER_COMMANDS_NAMESPACE . '\\' . $commandDirectoryName . '\\' . $subcommandStrategyClass
        )) {
            return new $containerCommandClass();
        }

        throw new InvalidArgumentException('Non-existing container command given');
    }
}
                                predis/src/Command/FactoryInterface.php                                                             0000644                 00000002116 15233650113 0014137 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command;

/**
 * Command factory interface.
 *
 * A command factory is used through the library to create instances of commands
 * classes implementing Predis\Command\CommandInterface mapped to Redis commands
 * by their command ID string (SET, GET, etc...).
 */
interface FactoryInterface
{
    /**
     * Checks if the command factory supports the specified list of commands.
     *
     * @param string ...$commandIDs List of command IDs
     *
     * @return bool
     */
    public function supports(string ...$commandIDs): bool;

    /**
     * Creates a new command instance.
     *
     * @param string $commandID Command ID
     * @param array  $arguments Arguments for the command
     *
     * @return CommandInterface
     */
    public function create(string $commandID, array $arguments = []): CommandInterface;
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Argument/Search/AggregateArguments.php                                           0000644                 00000010305 15233650113 0017451 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search;

class AggregateArguments extends CommonArguments
{
    /**
     * @var string[]
     */
    private $sortingEnum = [
        'asc' => 'ASC',
        'desc' => 'DESC',
    ];

    /**
     * Loads document attributes from the source document.
     *
     * @param  string ...$fields Could be just '*' to load all fields
     * @return $this
     */
    public function load(string ...$fields): self
    {
        $arguments = func_get_args();

        $this->arguments[] = 'LOAD';

        if ($arguments[0] === '*') {
            $this->arguments[] = '*';

            return $this;
        }

        $this->arguments[] = count($arguments);
        $this->arguments = array_merge($this->arguments, $arguments);

        return $this;
    }

    /**
     * Loads document attributes from the source document.
     *
     * @param  string ...$properties
     * @return $this
     */
    public function groupBy(string ...$properties): self
    {
        $arguments = func_get_args();

        array_push($this->arguments, 'GROUPBY', count($arguments));
        $this->arguments = array_merge($this->arguments, $arguments);

        return $this;
    }

    /**
     * Groups the results in the pipeline based on one or more properties.
     *
     * If you want to add alias property to your argument just add "true" value in arguments enumeration,
     * next value will be considered as alias to previous one.
     *
     * Example: 'argument', true, 'name' => 'argument' AS 'name'
     *
     * @param  string      $function
     * @param  string|bool ...$argument
     * @return $this
     */
    public function reduce(string $function, ...$argument): self
    {
        $arguments = func_get_args();
        $functionValue = array_shift($arguments);
        $argumentsCounter = 0;

        for ($i = 0, $iMax = count($arguments); $i < $iMax; $i++) {
            if (true === $arguments[$i]) {
                $arguments[$i] = 'AS';
                $i++;
                continue;
            }

            $argumentsCounter++;
        }

        array_push($this->arguments, 'REDUCE', $functionValue);
        $this->arguments = array_merge($this->arguments, [$argumentsCounter], $arguments);

        return $this;
    }

    /**
     * Sorts the pipeline up until the point of SORTBY, using a list of properties.
     *
     * @param  int    $max
     * @param  string ...$properties Enumeration of properties, including sorting direction (ASC, DESC)
     * @return $this
     */
    public function sortBy(int $max = 0, ...$properties): self
    {
        $arguments = func_get_args();
        $maxValue = array_shift($arguments);

        $this->arguments[] = 'SORTBY';
        $this->arguments = array_merge($this->arguments, [count($arguments)], $arguments);

        if ($maxValue !== 0) {
            array_push($this->arguments, 'MAX', $maxValue);
        }

        return $this;
    }

    /**
     * Applies a 1-to-1 transformation on one or more properties and either stores the result
     * as a new property down the pipeline or replaces any property using this transformation.
     *
     * @param  string $expression
     * @param  string $as
     * @return $this
     */
    public function apply(string $expression, string $as = ''): self
    {
        array_push($this->arguments, 'APPLY', $expression);

        if ($as !== '') {
            array_push($this->arguments, 'AS', $as);
        }

        return $this;
    }

    /**
     * Scan part of the results with a quicker alternative than LIMIT.
     *
     * @param  int   $readSize
     * @param  int   $idleTime
     * @return $this
     */
    public function withCursor(int $readSize = 0, int $idleTime = 0): self
    {
        $this->arguments[] = 'WITHCURSOR';

        if ($readSize !== 0) {
            array_push($this->arguments, 'COUNT', $readSize);
        }

        if ($idleTime !== 0) {
            array_push($this->arguments, 'MAXIDLE', $idleTime);
        }

        return $this;
    }
}
                                                                                                                                                                                                                                                                                                                           predis/src/Command/Argument/Search/SpellcheckArguments.php                                          0000644                 00000003042 15233650113 0017640 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search;

use InvalidArgumentException;

class SpellcheckArguments extends CommonArguments
{
    /**
     * @var string[]
     */
    private $termsEnum = [
        'include' => 'INCLUDE',
        'exclude' => 'EXCLUDE',
    ];

    /**
     * Is maximum Levenshtein distance for spelling suggestions (default: 1, max: 4).
     *
     * @return $this
     */
    public function distance(int $distance): self
    {
        $this->arguments[] = 'DISTANCE';
        $this->arguments[] = $distance;

        return $this;
    }

    /**
     * Specifies an inclusion (INCLUDE) or exclusion (EXCLUDE) of a custom dictionary named {dict}.
     *
     * @param  string $dictionary
     * @param  string $modifier
     * @param  string ...$terms
     * @return $this
     */
    public function terms(string $dictionary, string $modifier = 'INCLUDE', string ...$terms): self
    {
        if (!in_array(strtoupper($modifier), $this->termsEnum)) {
            $enumValues = implode(', ', array_values($this->termsEnum));
            throw new InvalidArgumentException("Wrong modifier value given. Currently supports: {$enumValues}");
        }

        array_push($this->arguments, 'TERMS', $this->termsEnum[strtolower($modifier)], $dictionary, ...$terms);

        return $this;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              predis/src/Command/Argument/Search/DropArguments.php                                                0000644                 00000001444 15233650113 0016473 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search;

use Predis\Command\Argument\ArrayableArgument;

class DropArguments implements ArrayableArgument
{
    /**
     * @var array
     */
    protected $arguments = [];

    /**
     * Drop operation that, if set, deletes the actual document hashes.
     *
     * @return $this
     */
    public function dd(): self
    {
        $this->arguments[] = 'DD';

        return $this;
    }

    /**
     * @return array
     */
    public function toArray(): array
    {
        return $this->arguments;
    }
}
                                                                                                                                                                                                                            predis/src/Command/Argument/Search/CommonArguments.php                                              0000644                 00000007723 15233650113 0017025 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search;

use Predis\Command\Argument\ArrayableArgument;

class CommonArguments implements ArrayableArgument
{
    /**
     * @var array
     */
    protected $arguments = [];

    /**
     * Adds default language for documents within an index.
     *
     * @param  string $defaultLanguage
     * @return $this
     */
    public function language(string $defaultLanguage = 'english'): self
    {
        $this->arguments[] = 'LANGUAGE';
        $this->arguments[] = $defaultLanguage;

        return $this;
    }

    /**
     * Selects the dialect version under which to execute the query.
     * If not specified, the query will execute under the default dialect version
     * set during module initial loading or via FT.CONFIG SET command.
     *
     * @param  string $dialect
     * @return $this
     */
    public function dialect(string $dialect): self
    {
        $this->arguments[] = 'DIALECT';
        $this->arguments[] = $dialect;

        return $this;
    }

    /**
     * If set, does not scan and index.
     *
     * @return $this
     */
    public function skipInitialScan(): self
    {
        $this->arguments[] = 'SKIPINITIALSCAN';

        return $this;
    }

    /**
     * Adds an arbitrary, binary safe payload that is exposed to custom scoring functions.
     *
     * @param  string $payload
     * @return $this
     */
    public function payload(string $payload): self
    {
        $this->arguments[] = 'PAYLOAD';
        $this->arguments[] = $payload;

        return $this;
    }

    /**
     * Also returns the relative internal score of each document.
     *
     * @return $this
     */
    public function withScores(): self
    {
        $this->arguments[] = 'WITHSCORES';

        return $this;
    }

    /**
     * Retrieves optional document payloads.
     *
     * @return $this
     */
    public function withPayloads(): self
    {
        $this->arguments[] = 'WITHPAYLOADS';

        return $this;
    }

    /**
     * Does not try to use stemming for query expansion but searches the query terms verbatim.
     *
     * @return $this
     */
    public function verbatim(): self
    {
        $this->arguments[] = 'VERBATIM';

        return $this;
    }

    /**
     * Overrides the timeout parameter of the module.
     *
     * @param  int   $timeout
     * @return $this
     */
    public function timeout(int $timeout): self
    {
        $this->arguments[] = 'TIMEOUT';
        $this->arguments[] = $timeout;

        return $this;
    }

    /**
     * Adds an arbitrary, binary safe payload that is exposed to custom scoring functions.
     *
     * @param  int   $offset
     * @param  int   $num
     * @return $this
     */
    public function limit(int $offset, int $num): self
    {
        array_push($this->arguments, 'LIMIT', $offset, $num);

        return $this;
    }

    /**
     * Adds filter expression into index.
     *
     * @param  string $filter
     * @return $this
     */
    public function filter(string $filter): self
    {
        $this->arguments[] = 'FILTER';
        $this->arguments[] = $filter;

        return $this;
    }

    /**
     * Defines one or more value parameters. Each parameter has a name and a value.
     *
     * Example: ['name1', 'value1', 'name2', 'value2'...]
     *
     * @param  array $nameValuesDictionary
     * @return $this
     */
    public function params(array $nameValuesDictionary): self
    {
        $this->arguments[] = 'PARAMS';
        $this->arguments[] = count($nameValuesDictionary);
        $this->arguments = array_merge($this->arguments, $nameValuesDictionary);

        return $this;
    }

    /**
     * {@inheritDoc}
     */
    public function toArray(): array
    {
        return $this->arguments;
    }
}
                                             predis/src/Command/Argument/Search/SynUpdateArguments.php                                           0000644                 00000000541 15233650113 0017500 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search;

class SynUpdateArguments extends CommonArguments
{
}
                                                                                                                                                               predis/src/Command/Argument/Search/SearchArguments.php                                              0000644                 00000020456 15233650113 0017000 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search;

use InvalidArgumentException;

class SearchArguments extends CommonArguments
{
    /**
     * @var string[]
     */
    private $sortingEnum = [
        'asc' => 'ASC',
        'desc' => 'DESC',
    ];

    /**
     * Returns the document ids and not the content.
     *
     * @return $this
     */
    public function noContent(): self
    {
        $this->arguments[] = 'NOCONTENT';

        return $this;
    }

    /**
     * Returns the value of the sorting key, right after the id and score and/or payload, if requested.
     *
     * @return $this
     */
    public function withSortKeys(): self
    {
        $this->arguments[] = 'WITHSORTKEYS';

        return $this;
    }

    /**
     * Limits results to those having numeric values ranging between min and max,
     * if numeric_attribute is defined as a numeric attribute in FT.CREATE.
     * Min and max follow ZRANGE syntax, and can be -inf, +inf, and use( for exclusive ranges.
     * Multiple numeric filters for different attributes are supported in one query.
     *
     * @param  array ...$filter Should contain: numeric_field, min and max. Example: ['numeric_field', 1, 10]
     * @return $this
     */
    public function searchFilter(array ...$filter): self
    {
        $arguments = func_get_args();

        foreach ($arguments as $argument) {
            array_push($this->arguments, 'FILTER', ...$argument);
        }

        return $this;
    }

    /**
     * Filter the results to a given radius from lon and lat. Radius is given as a number and units.
     *
     * @param  array ...$filter Should contain: geo_field, lon, lat, radius, unit. Example: ['geo_field', 34.1231, 35.1231, 300, km]
     * @return $this
     */
    public function geoFilter(array ...$filter): self
    {
        $arguments = func_get_args();

        foreach ($arguments as $argument) {
            array_push($this->arguments, 'GEOFILTER', ...$argument);
        }

        return $this;
    }

    /**
     * Limits the result to a given set of keys specified in the list.
     *
     * @param  array $keys
     * @return $this
     */
    public function inKeys(array $keys): self
    {
        $this->arguments[] = 'INKEYS';
        $this->arguments[] = count($keys);
        $this->arguments = array_merge($this->arguments, $keys);

        return $this;
    }

    /**
     * Filters the results to those appearing only in specific attributes of the document, like title or URL.
     *
     * @param  array $fields
     * @return $this
     */
    public function inFields(array $fields): self
    {
        $this->arguments[] = 'INFIELDS';
        $this->arguments[] = count($fields);
        $this->arguments = array_merge($this->arguments, $fields);

        return $this;
    }

    /**
     * Limits the attributes returned from the document.
     * Num is the number of attributes following the keyword.
     * If num is 0, it acts like NOCONTENT.
     * Identifier is either an attribute name (for hashes and JSON) or a JSON Path expression (for JSON).
     * Property is an optional name used in the result. If not provided, the identifier is used in the result.
     *
     * If you want to add alias property to your identifier just add "true" value in identifier enumeration,
     * next value will be considered as alias to previous one.
     *
     * Example: 'identifier', true, 'property' => 'identifier' AS 'property'
     *
     * @param  int         $count
     * @param  string|bool ...$identifier
     * @return $this
     */
    public function addReturn(int $count, ...$identifier): self
    {
        $arguments = func_get_args();

        $this->arguments[] = 'RETURN';

        for ($i = 1, $iMax = count($arguments); $i < $iMax; $i++) {
            if (true === $arguments[$i]) {
                $arguments[$i] = 'AS';
            }
        }

        $this->arguments = array_merge($this->arguments, $arguments);

        return $this;
    }

    /**
     * Returns only the sections of the attribute that contain the matched text.
     *
     * @param  array  $fields
     * @param  int    $frags
     * @param  int    $len
     * @param  string $separator
     * @return $this
     */
    public function summarize(array $fields = [], int $frags = 0, int $len = 0, string $separator = ''): self
    {
        $this->arguments[] = 'SUMMARIZE';

        if (!empty($fields)) {
            $this->arguments[] = 'FIELDS';
            $this->arguments[] = count($fields);
            $this->arguments = array_merge($this->arguments, $fields);
        }

        if ($frags !== 0) {
            $this->arguments[] = 'FRAGS';
            $this->arguments[] = $frags;
        }

        if ($len !== 0) {
            $this->arguments[] = 'LEN';
            $this->arguments[] = $len;
        }

        if ($separator !== '') {
            $this->arguments[] = 'SEPARATOR';
            $this->arguments[] = $separator;
        }

        return $this;
    }

    /**
     * Formats occurrences of matched text.
     *
     * @param  array  $fields
     * @param  string $openTag
     * @param  string $closeTag
     * @return $this
     */
    public function highlight(array $fields = [], string $openTag = '', string $closeTag = ''): self
    {
        $this->arguments[] = 'HIGHLIGHT';

        if (!empty($fields)) {
            $this->arguments[] = 'FIELDS';
            $this->arguments[] = count($fields);
            $this->arguments = array_merge($this->arguments, $fields);
        }

        if ($openTag !== '' && $closeTag !== '') {
            array_push($this->arguments, 'TAGS', $openTag, $closeTag);
        }

        return $this;
    }

    /**
     * Allows a maximum of N intervening number of unmatched offsets between phrase terms.
     * In other words, the slop for exact phrases is 0.
     *
     * @param  int   $slop
     * @return $this
     */
    public function slop(int $slop): self
    {
        $this->arguments[] = 'SLOP';
        $this->arguments[] = $slop;

        return $this;
    }

    /**
     * Puts the query terms in the same order in the document as in the query, regardless of the offsets between them.
     * Typically used in conjunction with SLOP.
     *
     * @return $this
     */
    public function inOrder(): self
    {
        $this->arguments[] = 'INORDER';

        return $this;
    }

    /**
     * Uses a custom query expander instead of the stemmer.
     *
     * @param  string $expander
     * @return $this
     */
    public function expander(string $expander): self
    {
        $this->arguments[] = 'EXPANDER';
        $this->arguments[] = $expander;

        return $this;
    }

    /**
     * Uses a custom scoring function you define.
     *
     * @param  string $scorer
     * @return $this
     */
    public function scorer(string $scorer): self
    {
        $this->arguments[] = 'SCORER';
        $this->arguments[] = $scorer;

        return $this;
    }

    /**
     * Returns a textual description of how the scores were calculated.
     * Using this options requires the WITHSCORES option.
     *
     * @return $this
     */
    public function explainScore(): self
    {
        $this->arguments[] = 'EXPLAINSCORE';

        return $this;
    }

    /**
     * Orders the results by the value of this attribute.
     * This applies to both text and numeric attributes.
     * Attributes needed for SORTBY should be declared as SORTABLE in the index, in order to be available with very low latency.
     * Note that this adds memory overhead.
     *
     * @param  string $sortAttribute
     * @param  string $orderBy
     * @return $this
     */
    public function sortBy(string $sortAttribute, string $orderBy = 'asc'): self
    {
        $this->arguments[] = 'SORTBY';
        $this->arguments[] = $sortAttribute;

        if (in_array(strtoupper($orderBy), $this->sortingEnum)) {
            $this->arguments[] = $this->sortingEnum[strtolower($orderBy)];
        } else {
            $enumValues = implode(', ', array_values($this->sortingEnum));
            throw new InvalidArgumentException("Wrong order direction value given. Currently supports: {$enumValues}");
        }

        return $this;
    }
}
                                                                                                                                                                                                                  predis/src/Command/Argument/Search/SugAddArguments.php                                              0000644                 00000001016 15233650113 0016731 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search;

class SugAddArguments extends CommonArguments
{
    /**
     * Adds INCR modifier.
     *
     * @return $this
     */
    public function incr(): self
    {
        $this->arguments[] = 'INCR';

        return $this;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  predis/src/Command/Argument/Search/ProfileArguments.php                                             0000644                 00000002641 15233650113 0017167 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search;

use Predis\Command\Argument\ArrayableArgument;

class ProfileArguments implements ArrayableArgument
{
    /**
     * @var array
     */
    protected $arguments = [];

    /**
     * Adds search context.
     *
     * @return $this
     */
    public function search(): self
    {
        $this->arguments[] = 'SEARCH';

        return $this;
    }

    /**
     * Adds aggregate context.
     *
     * @return $this
     */
    public function aggregate(): self
    {
        $this->arguments[] = 'AGGREGATE';

        return $this;
    }

    /**
     * Removes details of reader iterator.
     *
     * @return $this
     */
    public function limited(): self
    {
        $this->arguments[] = 'LIMITED';

        return $this;
    }

    /**
     * Is query string, as if sent to FT.SEARCH.
     *
     * @param  string $query
     * @return $this
     */
    public function query(string $query): self
    {
        $this->arguments[] = 'QUERY';
        $this->arguments[] = $query;

        return $this;
    }

    /**
     * {@inheritDoc}
     */
    public function toArray(): array
    {
        return $this->arguments;
    }
}
                                                                                               predis/src/Command/Argument/Search/AlterArguments.php                                               0000644                 00000000535 15233650113 0016636 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search;

class AlterArguments extends CommonArguments
{
}
                                                                                                                                                                   predis/src/Command/Argument/Search/CursorArguments.php                                              0000644                 00000001603 15233650113 0017041 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search;

use Predis\Command\Argument\ArrayableArgument;

class CursorArguments implements ArrayableArgument
{
    /**
     * @var array
     */
    protected $arguments = [];

    /**
     * Is number of results to read. This parameter overrides COUNT specified in FT.AGGREGATE.
     *
     * @param  int   $readSize
     * @return $this
     */
    public function count(int $readSize): self
    {
        array_push($this->arguments, 'COUNT', $readSize);

        return $this;
    }

    /**
     * {@inheritDoc}
     */
    public function toArray(): array
    {
        return $this->arguments;
    }
}
                                                                                                                             predis/src/Command/Argument/Search/SugGetArguments.php                                              0000644                 00000001543 15233650113 0016765 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search;

class SugGetArguments extends CommonArguments
{
    /**
     * Performs a fuzzy prefix search, including prefixes at Levenshtein distance of 1 from the prefix sent.
     *
     * @return $this
     */
    public function fuzzy(): self
    {
        $this->arguments[] = 'FUZZY';

        return $this;
    }

    /**
     * Limits the results to a maximum of num (default: 5).
     *
     * @param  int   $num
     * @return $this
     */
    public function max(int $num): self
    {
        array_push($this->arguments, 'MAX', $num);

        return $this;
    }
}
                                                                                                                                                             predis/src/Command/Argument/Search/CreateArguments.php                                              0000644                 00000010542 15233650113 0016771 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search;

use InvalidArgumentException;

class CreateArguments extends CommonArguments
{
    /**
     * @var string[]
     */
    private $supportedDataTypesEnum = [
        'hash' => 'HASH',
        'json' => 'JSON',
    ];

    /**
     * Specify data type for given index. To index JSON you must have the RedisJSON module to be installed.
     *
     * @param  string $modifier
     * @return $this
     */
    public function on(string $modifier = 'HASH'): self
    {
        if (in_array(strtoupper($modifier), $this->supportedDataTypesEnum)) {
            $this->arguments[] = 'ON';
            $this->arguments[] = $this->supportedDataTypesEnum[strtolower($modifier)];

            return $this;
        }

        $enumValues = implode(', ', array_values($this->supportedDataTypesEnum));
        throw new InvalidArgumentException("Wrong modifier value given. Currently supports: {$enumValues}");
    }

    /**
     * Adds one or more prefixes into index.
     *
     * @param  array $prefixes
     * @return $this
     */
    public function prefix(array $prefixes): self
    {
        $this->arguments[] = 'PREFIX';
        $this->arguments[] = count($prefixes);
        $this->arguments = array_merge($this->arguments, $prefixes);

        return $this;
    }

    /**
     * Document attribute set as document language.
     *
     * @param  string $languageAttribute
     * @return $this
     */
    public function languageField(string $languageAttribute): self
    {
        $this->arguments[] = 'LANGUAGE_FIELD';
        $this->arguments[] = $languageAttribute;

        return $this;
    }

    /**
     * Default score for documents in the index.
     *
     * @param  float $defaultScore
     * @return $this
     */
    public function score(float $defaultScore = 1.0): self
    {
        $this->arguments[] = 'SCORE';
        $this->arguments[] = $defaultScore;

        return $this;
    }

    /**
     * Document attribute that used as the document rank based on the user ranking.
     *
     * @param  string $scoreAttribute
     * @return $this
     */
    public function scoreField(string $scoreAttribute): self
    {
        $this->arguments[] = 'SCORE_FIELD';
        $this->arguments[] = $scoreAttribute;

        return $this;
    }

    /**
     * Forces RediSearch to encode indexes as if there were more than 32 text attributes.
     *
     * @return $this
     */
    public function maxTextFields(): self
    {
        $this->arguments[] = 'MAXTEXTFIELDS';

        return $this;
    }

    /**
     * Does not store term offsets for documents.
     *
     * @return $this
     */
    public function noOffsets(): self
    {
        $this->arguments[] = 'NOOFFSETS';

        return $this;
    }

    /**
     * Creates a lightweight temporary index that expires after a specified period of inactivity, in seconds.
     *
     * @param  int   $seconds
     * @return $this
     */
    public function temporary(int $seconds): self
    {
        $this->arguments[] = 'TEMPORARY';
        $this->arguments[] = $seconds;

        return $this;
    }

    /**
     * Conserves storage space and memory by disabling highlighting support.
     *
     * @return $this
     */
    public function noHl(): self
    {
        $this->arguments[] = 'NOHL';

        return $this;
    }

    /**
     * Does not store attribute bits for each term.
     *
     * @return $this
     */
    public function noFields(): self
    {
        $this->arguments[] = 'NOFIELDS';

        return $this;
    }

    /**
     * Avoids saving the term frequencies in the index.
     *
     * @return $this
     */
    public function noFreqs(): self
    {
        $this->arguments[] = 'NOFREQS';

        return $this;
    }

    /**
     * Sets the index with a custom stopword list, to be ignored during indexing and search time.
     *
     * @param  array $stopWords
     * @return $this
     */
    public function stopWords(array $stopWords): self
    {
        $this->arguments[] = 'STOPWORDS';
        $this->arguments[] = count($stopWords);
        $this->arguments = array_merge($this->arguments, $stopWords);

        return $this;
    }
}
                                                                                                                                                              predis/src/Command/Argument/Search/ExplainArguments.php                                             0000644                 00000000537 15233650113 0017171 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search;

class ExplainArguments extends CommonArguments
{
}
                                                                                                                                                                 predis/src/Command/Argument/Search/SchemaFields/TextField.php                                       0000644                 00000002730 15233650113 0020117 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search\SchemaFields;

class TextField extends AbstractField
{
    /**
     * @param string      $identifier
     * @param string      $alias
     * @param bool|string $sortable
     * @param bool        $noIndex
     * @param bool        $noStem
     * @param string      $phonetic
     * @param int         $weight
     * @param bool        $withSuffixTrie
     */
    public function __construct(
        string $identifier,
        string $alias = '',
        $sortable = self::NOT_SORTABLE,
        bool $noIndex = false,
        bool $noStem = false,
        string $phonetic = '',
        int $weight = 1,
        bool $withSuffixTrie = false
    ) {
        $this->setCommonOptions('TEXT', $identifier, $alias, $sortable, $noIndex);

        if ($noStem) {
            $this->fieldArguments[] = 'NOSTEM';
        }

        if ($phonetic !== '') {
            $this->fieldArguments[] = 'PHONETIC';
            $this->fieldArguments[] = $phonetic;
        }

        if ($weight !== 1) {
            $this->fieldArguments[] = 'WEIGHT';
            $this->fieldArguments[] = $weight;
        }

        if ($withSuffixTrie) {
            $this->fieldArguments[] = 'WITHSUFFIXTRIE';
        }
    }
}
                                        predis/src/Command/Argument/Search/SchemaFields/VectorField.php                                     0000644                 00000002165 15233650113 0020437 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search\SchemaFields;

class VectorField extends AbstractField
{
    /**
     * @var array
     */
    protected $fieldArguments = [];

    /**
     * @param string $fieldName
     * @param string $algorithm
     * @param array  $attributeNameValueDictionary
     * @param string $alias
     */
    public function __construct(
        string $fieldName,
        string $algorithm,
        array $attributeNameValueDictionary,
        string $alias = ''
    ) {
        $this->setCommonOptions('VECTOR', $fieldName, $alias);

        array_push($this->fieldArguments, $algorithm, count($attributeNameValueDictionary));
        $this->fieldArguments = array_merge($this->fieldArguments, $attributeNameValueDictionary);
    }

    /**
     * {@inheritDoc}
     */
    public function toArray(): array
    {
        return $this->fieldArguments;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Argument/Search/SchemaFields/AbstractField.php                                   0000644                 00000003215 15233650113 0020735 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search\SchemaFields;

abstract class AbstractField implements FieldInterface
{
    public const SORTABLE = true;
    public const NOT_SORTABLE = false;
    public const SORTABLE_UNF = 'UNF';

    /**
     * @var array
     */
    protected $fieldArguments = [];

    /**
     * @param  string      $fieldType
     * @param  string      $identifier
     * @param  string      $alias
     * @param  bool|string $sortable
     * @param  bool        $noIndex
     * @return void
     */
    protected function setCommonOptions(
        string $fieldType,
        string $identifier,
        string $alias = '',
        $sortable = self::NOT_SORTABLE,
        bool $noIndex = false
    ): void {
        $this->fieldArguments[] = $identifier;

        if ($alias !== '') {
            $this->fieldArguments[] = 'AS';
            $this->fieldArguments[] = $alias;
        }

        $this->fieldArguments[] = $fieldType;

        if ($sortable === self::SORTABLE) {
            $this->fieldArguments[] = 'SORTABLE';
        } elseif ($sortable === self::SORTABLE_UNF) {
            $this->fieldArguments[] = 'SORTABLE';
            $this->fieldArguments[] = 'UNF';
        }

        if ($noIndex) {
            $this->fieldArguments[] = 'NOINDEX';
        }
    }

    /**
     * {@inheritDoc}
     */
    public function toArray(): array
    {
        return $this->fieldArguments;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                   predis/src/Command/Argument/Search/SchemaFields/FieldInterface.php                                  0000644                 00000000716 15233650113 0021075 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search\SchemaFields;

use Predis\Command\Argument\ArrayableArgument;

/**
 * Represents field in search schema.
 */
interface FieldInterface extends ArrayableArgument
{
}
                                                  predis/src/Command/Argument/Search/SchemaFields/GeoField.php                                        0000644                 00000001377 15233650113 0017713 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search\SchemaFields;

class GeoField extends AbstractField
{
    /**
     * @param string      $identifier
     * @param string      $alias
     * @param bool|string $sortable
     * @param bool        $noIndex
     */
    public function __construct(
        string $identifier,
        string $alias = '',
        $sortable = self::NOT_SORTABLE,
        bool $noIndex = false
    ) {
        $this->setCommonOptions('GEO', $identifier, $alias, $sortable, $noIndex);
    }
}
                                                                                                                                                                                                                                                                 predis/src/Command/Argument/Search/SchemaFields/NumericField.php                                    0000644                 00000001407 15233650113 0020575 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search\SchemaFields;

class NumericField extends AbstractField
{
    /**
     * @param string      $identifier
     * @param string      $alias
     * @param bool|string $sortable
     * @param bool        $noIndex
     */
    public function __construct(
        string $identifier,
        string $alias = '',
        $sortable = self::NOT_SORTABLE,
        bool $noIndex = false
    ) {
        $this->setCommonOptions('NUMERIC', $identifier, $alias, $sortable, $noIndex);
    }
}
                                                                                                                                                                                                                                                         predis/src/Command/Argument/Search/SchemaFields/TagField.php                                        0000644                 00000002205 15233650113 0017703 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Search\SchemaFields;

class TagField extends AbstractField
{
    /**
     * @param string      $identifier
     * @param string      $alias
     * @param bool|string $sortable
     * @param bool        $noIndex
     * @param string      $separator
     * @param bool        $caseSensitive
     */
    public function __construct(
        string $identifier,
        string $alias = '',
        $sortable = self::NOT_SORTABLE,
        bool $noIndex = false,
        string $separator = ',',
        bool $caseSensitive = false
    ) {
        $this->setCommonOptions('TAG', $identifier, $alias, $sortable, $noIndex);

        if ($separator !== ',') {
            $this->fieldArguments[] = 'SEPARATOR';
            $this->fieldArguments[] = $separator;
        }

        if ($caseSensitive) {
            $this->fieldArguments[] = 'CASESENSITIVE';
        }
    }
}
                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Argument/Geospatial/FromMember.php                                               0000644                 00000001245 15233650113 0016616 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Geospatial;

class FromMember implements FromInterface
{
    private const KEYWORD = 'FROMMEMBER';

    /**
     * @var string
     */
    private $member;

    public function __construct(string $member)
    {
        $this->member = $member;
    }

    /**
     * {@inheritDoc}
     */
    public function toArray(): array
    {
        return [self::KEYWORD, $this->member];
    }
}
                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Argument/Geospatial/FromLonLat.php                                               0000644                 00000001463 15233650113 0016602 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Geospatial;

class FromLonLat implements FromInterface
{
    private const KEYWORD = 'FROMLONLAT';

    /**
     * @var float
     */
    private $longitude;

    /**
     * @var float
     */
    private $latitude;

    public function __construct(float $longitude, float $latitude)
    {
        $this->longitude = $longitude;
        $this->latitude = $latitude;
    }

    /**
     * {@inheritDoc}
     */
    public function toArray(): array
    {
        return [self::KEYWORD, $this->longitude, $this->latitude];
    }
}
                                                                                                                                                                                                             predis/src/Command/Argument/Geospatial/AbstractBy.php                                               0000644                 00000001634 15233650113 0016623 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Geospatial;

use UnexpectedValueException;

abstract class AbstractBy implements ByInterface
{
    /**
     * @var string[]
     */
    private static $unitEnum = ['m', 'km', 'ft', 'mi'];

    /**
     * @var string
     */
    protected $unit;

    /**
     * {@inheritDoc}
     */
    abstract public function toArray(): array;

    /**
     * @param  string $unit
     * @return void
     */
    protected function setUnit(string $unit): void
    {
        if (!in_array($unit, self::$unitEnum, true)) {
            throw new UnexpectedValueException('Wrong value given for unit');
        }

        $this->unit = $unit;
    }
}
                                                                                                    predis/src/Command/Argument/Geospatial/FromInterface.php                                            0000644                 00000000626 15233650113 0017311 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Geospatial;

use Predis\Command\Argument\ArrayableArgument;

interface FromInterface extends ArrayableArgument
{
}
                                                                                                          predis/src/Command/Argument/Geospatial/ByInterface.php                                              0000644                 00000000624 15233650113 0016756 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Geospatial;

use Predis\Command\Argument\ArrayableArgument;

interface ByInterface extends ArrayableArgument
{
}
                                                                                                            predis/src/Command/Argument/Geospatial/ByRadius.php                                                 0000644                 00000001317 15233650113 0016305 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Geospatial;

class ByRadius extends AbstractBy
{
    private const KEYWORD = 'BYRADIUS';

    /**
     * @var int
     */
    private $radius;

    public function __construct(int $radius, string $unit)
    {
        $this->radius = $radius;
        $this->setUnit($unit);
    }

    /**
     * {@inheritDoc}
     */
    public function toArray(): array
    {
        return [self::KEYWORD, $this->radius, $this->unit];
    }
}
                                                                                                                                                                                                                                                                                                                 predis/src/Command/Argument/Geospatial/ByBox.php                                                    0000644                 00000001467 15233650113 0015614 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Geospatial;

class ByBox extends AbstractBy
{
    private const KEYWORD = 'BYBOX';

    /**
     * @var int
     */
    private $width;

    /**
     * @var int
     */
    private $height;

    public function __construct(int $width, int $height, string $unit)
    {
        $this->width = $width;
        $this->height = $height;
        $this->setUnit($unit);
    }

    /**
     * {@inheritDoc}
     */
    public function toArray(): array
    {
        return [self::KEYWORD, $this->width, $this->height, $this->unit];
    }
}
                                                                                                                                                                                                         predis/src/Command/Argument/Server/LimitInterface.php                                               0000644                 00000000623 15233650113 0016637 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Server;

use Predis\Command\Argument\ArrayableArgument;

interface LimitInterface extends ArrayableArgument
{
}
                                                                                                             predis/src/Command/Argument/Server/LimitOffsetCount.php                                             0000644                 00000001413 15233650113 0017174 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Server;

class LimitOffsetCount implements LimitInterface
{
    private const KEYWORD = 'LIMIT';

    /**
     * @var int
     */
    private $offset;

    /**
     * @var int
     */
    private $count;

    public function __construct(int $offset, int $count)
    {
        $this->offset = $offset;
        $this->count = $count;
    }

    /**
     * {@inheritDoc}
     */
    public function toArray(): array
    {
        return [self::KEYWORD, $this->offset, $this->count];
    }
}
                                                                                                                                                                                                                                                     predis/src/Command/Argument/Server/To.php                                                           0000644                 00000002074 15233650113 0014324 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\Server;

use Predis\Command\Argument\ArrayableArgument;

class To implements ArrayableArgument
{
    private const KEYWORD = 'TO';
    private const FORCE_KEYWORD = 'FORCE';

    /**
     * @var string
     */
    private $host;

    /**
     * @var int
     */
    private $port;

    /**
     * @var bool
     */
    private $isForce;

    public function __construct(string $host, int $port, bool $isForce = false)
    {
        $this->host = $host;
        $this->port = $port;
        $this->isForce = $isForce;
    }

    /**
     * {@inheritDoc}
     */
    public function toArray(): array
    {
        $arguments = [self::KEYWORD, $this->host, $this->port];

        if ($this->isForce) {
            $arguments[] = self::FORCE_KEYWORD;
        }

        return $arguments;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                    predis/src/Command/Argument/ArrayableArgument.php                                                   0000644                 00000001027 15233650113 0016076 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument;

/**
 * Allows to use object-oriented approach to handle complex conditional arguments.
 */
interface ArrayableArgument
{
    /**
     * Get the instance as an array.
     *
     * @return array
     */
    public function toArray(): array;
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         predis/src/Command/Argument/TimeSeries/MRangeArguments.php                                          0000644                 00000002154 15233650113 0017603 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\TimeSeries;

class MRangeArguments extends RangeArguments
{
    /**
     * Filters time series based on their labels and label values.
     *
     * @param  string ...$filterExpressions
     * @return $this
     */
    public function filter(string ...$filterExpressions): self
    {
        array_push($this->arguments, 'FILTER', ...$filterExpressions);

        return $this;
    }

    /**
     * Splits time series into groups, each group contains time series that share the same
     * value for the provided label name, then aggregates results in each group.
     *
     * @param  string $label
     * @param  string $reducer
     * @return $this
     */
    public function groupBy(string $label, string $reducer): self
    {
        array_push($this->arguments, 'GROUPBY', $label, 'REDUCE', $reducer);

        return $this;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                    predis/src/Command/Argument/TimeSeries/RangeArguments.php                                           0000644                 00000004414 15233650113 0017467 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\TimeSeries;

class RangeArguments extends CommonArguments
{
    /**
     * Filters samples by a list of specific timestamps.
     *
     * @param  int   ...$ts
     * @return $this
     */
    public function filterByTs(int ...$ts): self
    {
        array_push($this->arguments, 'FILTER_BY_TS', ...$ts);

        return $this;
    }

    /**
     * Filters samples by minimum and maximum values.
     *
     * @param  int   $min
     * @param  int   $max
     * @return $this
     */
    public function filterByValue(int $min, int $max): self
    {
        array_push($this->arguments, 'FILTER_BY_VALUE', $min, $max);

        return $this;
    }

    /**
     * Limits the number of returned samples.
     *
     * @param  int   $count
     * @return $this
     */
    public function count(int $count): self
    {
        array_push($this->arguments, 'COUNT', $count);

        return $this;
    }

    /**
     * Aggregates samples into time buckets.
     *
     * @param  string $aggregator
     * @param  int    $bucketDuration  Is duration of each bucket, in milliseconds.
     * @param  int    $align           It controls the time bucket timestamps by changing the reference timestamp on which a bucket is defined.
     * @param  int    $bucketTimestamp Controls how bucket timestamps are reported.
     * @param  bool   $empty           Is a flag, which, when specified, reports aggregations also for empty buckets.
     * @return $this
     */
    public function aggregation(string $aggregator, int $bucketDuration, int $align = 0, int $bucketTimestamp = 0, bool $empty = false): self
    {
        if ($align > 0) {
            array_push($this->arguments, 'ALIGN', $align);
        }

        array_push($this->arguments, 'AGGREGATION', $aggregator, $bucketDuration);

        if ($bucketTimestamp > 0) {
            array_push($this->arguments, 'BUCKETTIMESTAMP', $bucketTimestamp);
        }

        if (true === $empty) {
            $this->arguments[] = 'EMPTY';
        }

        return $this;
    }
}
                                                                                                                                                                                                                                                    predis/src/Command/Argument/TimeSeries/MGetArguments.php                                            0000644                 00000000540 15233650113 0017263 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\TimeSeries;

class MGetArguments extends CommonArguments
{
}
                                                                                                                                                                predis/src/Command/Argument/TimeSeries/DecrByArguments.php                                          0000644                 00000000542 15233650113 0017601 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\TimeSeries;

class DecrByArguments extends IncrByArguments
{
}
                                                                                                                                                              predis/src/Command/Argument/TimeSeries/IncrByArguments.php                                          0000644                 00000001645 15233650113 0017624 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\TimeSeries;

class IncrByArguments extends CommonArguments
{
    /**
     * Is (integer) UNIX sample timestamp in milliseconds or * to set the timestamp according to the server clock.
     *
     * @param  string|int $timeStamp
     * @return $this
     */
    public function timestamp($timeStamp): self
    {
        array_push($this->arguments, 'TIMESTAMP', $timeStamp);

        return $this;
    }

    /**
     * Changes data storage from compressed (default) to uncompressed.
     *
     * @return $this
     */
    public function uncompressed(): self
    {
        $this->arguments[] = 'UNCOMPRESSED';

        return $this;
    }
}
                                                                                           predis/src/Command/Argument/TimeSeries/CommonArguments.php                                          0000644                 00000006570 15233650113 0017670 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\TimeSeries;

use Predis\Command\Argument\ArrayableArgument;

class CommonArguments implements ArrayableArgument
{
    public const POLICY_BLOCK = 'BLOCK';
    public const POLICY_FIRST = 'FIRST';
    public const POLICY_LAST = 'LAST';
    public const POLICY_MIN = 'MIN';
    public const POLICY_MAX = 'MAX';
    public const POLICY_SUM = 'SUM';

    public const ENCODING_UNCOMPRESSED = 'UNCOMPRESSED';
    public const ENCODING_COMPRESSED = 'COMPRESSED';

    /**
     * @var array
     */
    protected $arguments = [];

    /**
     * Is maximum age for samples compared to the highest reported timestamp, in milliseconds.
     *
     * @param  int   $retentionPeriod
     * @return $this
     */
    public function retentionMsecs(int $retentionPeriod): self
    {
        array_push($this->arguments, 'RETENTION', $retentionPeriod);

        return $this;
    }

    /**
     * Is initial allocation size, in bytes, for the data part of each new chunk.
     *
     * @param  int   $size
     * @return $this
     */
    public function chunkSize(int $size): self
    {
        array_push($this->arguments, 'CHUNK_SIZE', $size);

        return $this;
    }

    /**
     * Is policy for handling insertion of multiple samples with identical timestamps.
     *
     * @param  string $policy
     * @return $this
     */
    public function duplicatePolicy(string $policy = self::POLICY_BLOCK): self
    {
        array_push($this->arguments, 'DUPLICATE_POLICY', $policy);

        return $this;
    }

    /**
     * Is set of label-value pairs that represent metadata labels of the key and serve as a secondary index.
     *
     * @param  mixed ...$labelValuePair
     * @return $this
     */
    public function labels(...$labelValuePair): self
    {
        array_push($this->arguments, 'LABELS', ...$labelValuePair);

        return $this;
    }

    /**
     * Specifies the series samples encoding format.
     *
     * @param  string $encoding
     * @return $this
     */
    public function encoding(string $encoding = self::ENCODING_COMPRESSED): self
    {
        array_push($this->arguments, 'ENCODING', $encoding);

        return $this;
    }

    /**
     * Is used when a time series is a compaction.
     * With LATEST, TS.GET reports the compacted value of the latest, possibly partial, bucket.
     *
     * @return $this
     */
    public function latest(): self
    {
        $this->arguments[] = 'LATEST';

        return $this;
    }

    /**
     * Includes in the reply all label-value pairs representing metadata labels of the time series.
     *
     * @return $this
     */
    public function withLabels(): self
    {
        $this->arguments[] = 'WITHLABELS';

        return $this;
    }

    /**
     * Returns a subset of the label-value pairs that represent metadata labels of the time series.
     *
     * @return $this
     */
    public function selectedLabels(string ...$labels): self
    {
        array_push($this->arguments, 'SELECTED_LABELS', ...$labels);

        return $this;
    }

    /**
     * {@inheritDoc}
     */
    public function toArray(): array
    {
        return $this->arguments;
    }
}
                                                                                                                                        predis/src/Command/Argument/TimeSeries/GetArguments.php                                             0000644                 00000000537 15233650113 0017154 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\TimeSeries;

class GetArguments extends CommonArguments
{
}
                                                                                                                                                                 predis/src/Command/Argument/TimeSeries/AddArguments.php                                             0000644                 00000001341 15233650113 0017117 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\TimeSeries;

class AddArguments extends CommonArguments
{
    /**
     * Is overwrite key and database configuration for DUPLICATE_POLICY,
     * the policy for handling samples with identical timestamps.
     *
     * @param  string $policy
     * @return $this
     */
    public function onDuplicate(string $policy = self::POLICY_BLOCK): self
    {
        array_push($this->arguments, 'ON_DUPLICATE', $policy);

        return $this;
    }
}
                                                                                                                                                                                                                                                                                               predis/src/Command/Argument/TimeSeries/AlterArguments.php                                           0000644                 00000000541 15233650113 0017477 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\TimeSeries;

class AlterArguments extends CommonArguments
{
}
                                                                                                                                                               predis/src/Command/Argument/TimeSeries/CreateArguments.php                                          0000644                 00000000542 15233650113 0017634 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\TimeSeries;

class CreateArguments extends CommonArguments
{
}
                                                                                                                                                              predis/src/Command/Argument/TimeSeries/InfoArguments.php                                            0000644                 00000001464 15233650113 0017330 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Argument\TimeSeries;

use Predis\Command\Argument\ArrayableArgument;

class InfoArguments implements ArrayableArgument
{
    /**
     * @var array
     */
    private $arguments = [];

    /**
     * Is an optional flag to get a more detailed information about the chunks.
     *
     * @return $this
     */
    public function debug(): self
    {
        $this->arguments[] = 'DEBUG';

        return $this;
    }

    /**
     * {@inheritDoc}
     */
    public function toArray(): array
    {
        return $this->arguments;
    }
}
                                                                                                                                                                                                            predis/src/Command/Traits/To/ServerTo.php                                                           0000644                 00000002340 15233650113 0014307 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\To;

use Predis\Command\Argument\Server\To;

trait ServerTo
{
    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$toArgumentPositionOffset >= $argumentsLength) {
            parent::setArguments($arguments);

            return;
        }

        /** @var To|null $toArgument */
        $toArgument = $arguments[static::$toArgumentPositionOffset];

        if (null === $toArgument) {
            array_splice($arguments, static::$toArgumentPositionOffset, 1, [false]);
            parent::setArguments($arguments);

            return;
        }

        $argumentsBefore = array_slice($arguments, 0, static::$toArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$toArgumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            $toArgument->toArray(),
            $argumentsAfter
        ));
    }
}
                                                                                                                                                                                                                                                                                                predis/src/Command/Traits/MinMaxModifier.php                                                        0000644                 00000002012 15233650113 0015020 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits;

use Predis\Command\Command;
use UnexpectedValueException;

/**
 * @mixin Command
 */
trait MinMaxModifier
{
    /**
     * @var array{string: string}
     */
    private $modifierEnum = [
        'min' => 'MIN',
        'max' => 'MAX',
    ];

    public function resolveModifier(int $offset, array &$arguments): void
    {
        if ($offset >= count($arguments)) {
            $arguments[$offset] = $this->modifierEnum['min'];

            return;
        }

        if (!is_string($arguments[$offset]) || !array_key_exists($arguments[$offset], $this->modifierEnum)) {
            throw new UnexpectedValueException('Wrong type of modifier given');
        }

        $arguments[$offset] = $this->modifierEnum[$arguments[$offset]];
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      predis/src/Command/Traits/Get/Get.php                                                               0000644                 00000002404 15233650113 0013413 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\Get;

use UnexpectedValueException;

trait Get
{
    private static $getModifier = 'GET';

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$getArgumentPositionOffset >= $argumentsLength) {
            parent::setArguments($arguments);

            return;
        }

        if (!is_array($arguments[static::$getArgumentPositionOffset])) {
            throw new UnexpectedValueException('Wrong get argument type');
        }

        $patterns = [];

        foreach ($arguments[static::$getArgumentPositionOffset] as $pattern) {
            $patterns[] = self::$getModifier;
            $patterns[] = $pattern;
        }

        $argumentsBeforeKeys = array_slice($arguments, 0, static::$getArgumentPositionOffset);
        $argumentsAfterKeys = array_slice($arguments, static::$getArgumentPositionOffset + 1);

        parent::setArguments(array_merge($argumentsBeforeKeys, $patterns, $argumentsAfterKeys));
    }
}
                                                                                                                                                                                                                                                            predis/src/Command/Traits/Weights.php                                                               0000644                 00000003002 15233650113 0013562 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits;

use Predis\Command\Command;
use UnexpectedValueException;

/**
 * @mixin Command
 */
trait Weights
{
    /**
     * @var string
     */
    private static $weightsModifier = 'WEIGHTS';

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$weightsArgumentPositionOffset >= $argumentsLength) {
            parent::setArguments($arguments);

            return;
        }

        if (!is_array($arguments[static::$weightsArgumentPositionOffset])) {
            throw new UnexpectedValueException('Wrong weights argument type');
        }

        $weightsArray = $arguments[static::$weightsArgumentPositionOffset];

        if (empty($weightsArray)) {
            unset($arguments[static::$weightsArgumentPositionOffset]);
            parent::setArguments($arguments);

            return;
        }

        $argumentsBefore = array_slice($arguments, 0, static::$weightsArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$weightsArgumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            [self::$weightsModifier],
            $weightsArray,
            $argumentsAfter
        ));
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              predis/src/Command/Traits/BitByte.php                                                               0000644                 00000001521 15233650113 0013516 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits;

trait BitByte
{
    private static $argumentEnum = [
        'bit' => 'BIT',
        'byte' => 'BYTE',
    ];

    public function setArguments(array $arguments)
    {
        $value = array_pop($arguments);

        if (null === $value) {
            parent::setArguments($arguments);

            return;
        }

        if (in_array(strtoupper($value), self::$argumentEnum, true)) {
            $arguments[] = self::$argumentEnum[$value];
        } else {
            $arguments[] = $value;
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                               predis/src/Command/Traits/Aggregate.php                                                             0000644                 00000003305 15233650113 0014044 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits;

use Predis\Command\Command;
use UnexpectedValueException;

/**
 * @mixin Command
 */
trait Aggregate
{
    /**
     * @var string[]
     */
    private static $aggregateValuesEnum = [
        'min' => 'MIN',
        'max' => 'MAX',
        'sum' => 'SUM',
    ];

    /**
     * @var string
     */
    private static $aggregateModifier = 'AGGREGATE';

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$aggregateArgumentPositionOffset >= $argumentsLength) {
            parent::setArguments($arguments);

            return;
        }

        $argument = $arguments[static::$aggregateArgumentPositionOffset];

        if (is_string($argument) && in_array(strtoupper($argument), self::$aggregateValuesEnum)) {
            $argument = self::$aggregateValuesEnum[$argument];
        } else {
            $enumValues = implode(', ', array_keys(self::$aggregateValuesEnum));
            throw new UnexpectedValueException("Aggregate argument accepts only: {$enumValues} values");
        }

        $argumentsBefore = array_slice($arguments, 0, static::$aggregateArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$aggregateArgumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            [self::$aggregateModifier],
            [$argument],
            $argumentsAfter
        ));
    }
}
                                                                                                                                                                                                                                                                                                                           predis/src/Command/Traits/BloomFilters/Capacity.php                                                 0000644                 00000003066 15233650113 0016320 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\BloomFilters;

use Predis\Command\Command;
use UnexpectedValueException;

/**
 * @mixin Command
 */
trait Capacity
{
    private static $capacityModifier = 'CAPACITY';

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$capacityArgumentPositionOffset >= $argumentsLength) {
            parent::setArguments($arguments);

            return;
        }

        if ($arguments[static::$capacityArgumentPositionOffset] === -1) {
            array_splice($arguments, static::$capacityArgumentPositionOffset, 1, [false]);
            parent::setArguments($arguments);

            return;
        }

        if ($arguments[static::$capacityArgumentPositionOffset] < 1) {
            throw new UnexpectedValueException('Wrong capacity argument value or position offset');
        }

        $argument = $arguments[static::$capacityArgumentPositionOffset];
        $argumentsBefore = array_slice($arguments, 0, static::$capacityArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$capacityArgumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            [self::$capacityModifier],
            [$argument],
            $argumentsAfter
        ));
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                          predis/src/Command/Traits/BloomFilters/BucketSize.php                                               0000644                 00000003117 15233650113 0016630 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\BloomFilters;

use Predis\Command\Command;
use UnexpectedValueException;

/**
 * @mixin Command
 */
trait BucketSize
{
    private static $bucketSizeModifier = 'BUCKETSIZE';

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$bucketSizeArgumentPositionOffset >= $argumentsLength) {
            parent::setArguments($arguments);

            return;
        }

        if ($arguments[static::$bucketSizeArgumentPositionOffset] === -1) {
            array_splice($arguments, static::$bucketSizeArgumentPositionOffset, 1, [false]);
            parent::setArguments($arguments);

            return;
        }

        if ($arguments[static::$bucketSizeArgumentPositionOffset] < 1) {
            throw new UnexpectedValueException('Wrong bucket size argument value or position offset');
        }

        $argument = $arguments[static::$bucketSizeArgumentPositionOffset];
        $argumentsBefore = array_slice($arguments, 0, static::$bucketSizeArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$bucketSizeArgumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            [self::$bucketSizeModifier],
            [$argument],
            $argumentsAfter
        ));
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                 predis/src/Command/Traits/BloomFilters/MaxIterations.php                                            0000644                 00000003163 15233650113 0017350 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\BloomFilters;

use Predis\Command\Command;
use UnexpectedValueException;

/**
 * @mixin Command
 */
trait MaxIterations
{
    private static $maxIterationsModifier = 'MAXITERATIONS';

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$maxIterationsArgumentPositionOffset >= $argumentsLength) {
            parent::setArguments($arguments);

            return;
        }

        if ($arguments[static::$maxIterationsArgumentPositionOffset] === -1) {
            array_splice($arguments, static::$maxIterationsArgumentPositionOffset, 1, [false]);
            parent::setArguments($arguments);

            return;
        }

        if ($arguments[static::$maxIterationsArgumentPositionOffset] < 1) {
            throw new UnexpectedValueException('Wrong max iterations argument value or position offset');
        }

        $argument = $arguments[static::$maxIterationsArgumentPositionOffset];
        $argumentsBefore = array_slice($arguments, 0, static::$maxIterationsArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$maxIterationsArgumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            [self::$maxIterationsModifier],
            [$argument],
            $argumentsAfter
        ));
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                             predis/src/Command/Traits/BloomFilters/Items.php                                                    0000644                 00000002127 15233650113 0015641 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\BloomFilters;

use Predis\Command\Command;

/**
 * @mixin Command
 */
trait Items
{
    private static $itemsModifier = 'ITEMS';

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$itemsArgumentPositionOffset >= $argumentsLength) {
            parent::setArguments($arguments);

            return;
        }

        $argument = $arguments[static::$itemsArgumentPositionOffset];
        $argumentsBefore = array_slice($arguments, 0, static::$itemsArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$itemsArgumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            [self::$itemsModifier],
            [$argument],
            $argumentsAfter
        ));
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                         predis/src/Command/Traits/BloomFilters/NoCreate.php                                                 0000644                 00000002432 15233650113 0016257 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\BloomFilters;

use Predis\Command\Command;
use UnexpectedValueException;

/**
 * @mixin Command
 */
trait NoCreate
{
    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (
            static::$noCreateArgumentPositionOffset >= $argumentsLength
            || false === $arguments[static::$noCreateArgumentPositionOffset]
        ) {
            parent::setArguments($arguments);

            return;
        }

        $argument = $arguments[static::$noCreateArgumentPositionOffset];

        if (true === $argument) {
            $argument = 'NOCREATE';
        } else {
            throw new UnexpectedValueException('Wrong NOCREATE argument type');
        }

        $argumentsBefore = array_slice($arguments, 0, static::$noCreateArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$noCreateArgumentPositionOffset + 1);

        parent::setArguments(array_merge($argumentsBefore, [$argument], $argumentsAfter));
    }
}
                                                                                                                                                                                                                                      predis/src/Command/Traits/BloomFilters/Expansion.php                                                0000644                 00000003014 15233650113 0016520 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\BloomFilters;

use UnexpectedValueException;

trait Expansion
{
    private static $expansionModifier = 'EXPANSION';

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$expansionArgumentPositionOffset >= $argumentsLength) {
            parent::setArguments($arguments);

            return;
        }

        if ($arguments[static::$expansionArgumentPositionOffset] === -1) {
            array_splice($arguments, static::$expansionArgumentPositionOffset, 1, [false]);
            parent::setArguments($arguments);

            return;
        }

        if ($arguments[static::$expansionArgumentPositionOffset] < 1) {
            throw new UnexpectedValueException('Wrong expansion argument value or position offset');
        }

        $argument = $arguments[static::$expansionArgumentPositionOffset];
        $argumentsBefore = array_slice($arguments, 0, static::$expansionArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$expansionArgumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            [self::$expansionModifier],
            [$argument],
            $argumentsAfter
        ));
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    predis/src/Command/Traits/BloomFilters/Error.php                                                    0000644                 00000003022 15233650113 0015644 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\BloomFilters;

use Predis\Command\Command;
use UnexpectedValueException;

/**
 * @mixin Command
 */
trait Error
{
    private static $errorModifier = 'ERROR';

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$errorArgumentPositionOffset >= $argumentsLength) {
            parent::setArguments($arguments);

            return;
        }

        if ($arguments[static::$errorArgumentPositionOffset] === -1) {
            array_splice($arguments, static::$errorArgumentPositionOffset, 1, [false]);
            parent::setArguments($arguments);

            return;
        }

        if ($arguments[static::$errorArgumentPositionOffset] < 0) {
            throw new UnexpectedValueException('Wrong error argument value or position offset');
        }

        $argument = $arguments[static::$errorArgumentPositionOffset];
        $argumentsBefore = array_slice($arguments, 0, static::$errorArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$errorArgumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            [self::$errorModifier],
            [$argument],
            $argumentsAfter
        ));
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              predis/src/Command/Traits/Timeout.php                                                               0000644                 00000002747 15233650113 0013615 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits;

use UnexpectedValueException;

trait Timeout
{
    private static $timeoutModifier = 'TIMEOUT';

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$timeoutArgumentPositionOffset >= $argumentsLength) {
            parent::setArguments($arguments);

            return;
        }

        if ($arguments[static::$timeoutArgumentPositionOffset] === -1) {
            array_splice($arguments, static::$timeoutArgumentPositionOffset, 1, [false]);
            parent::setArguments($arguments);

            return;
        }

        if ($arguments[static::$timeoutArgumentPositionOffset] < 1) {
            throw new UnexpectedValueException('Wrong timeout argument value or position offset');
        }

        $argument = $arguments[static::$timeoutArgumentPositionOffset];
        $argumentsBefore = array_slice($arguments, 0, static::$timeoutArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$timeoutArgumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            [self::$timeoutModifier],
            [$argument],
            $argumentsAfter
        ));
    }
}
                         predis/src/Command/Traits/Storedist.php                                                             0000644                 00000002425 15233650113 0014140 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits;

use Predis\Command\Command;
use UnexpectedValueException;

/**
 * @mixin Command
 */
trait Storedist
{
    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (
            static::$storeDistArgumentPositionOffset >= $argumentsLength
            || false === $arguments[static::$storeDistArgumentPositionOffset]
        ) {
            parent::setArguments($arguments);

            return;
        }

        $argument = $arguments[static::$storeDistArgumentPositionOffset];

        if (true === $argument) {
            $argument = 'STOREDIST';
        } else {
            throw new UnexpectedValueException('Wrong STOREDIST argument type');
        }

        $argumentsBefore = array_slice($arguments, 0, static::$storeDistArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$storeDistArgumentPositionOffset + 1);

        parent::setArguments(array_merge($argumentsBefore, [$argument], $argumentsAfter));
    }
}
                                                                                                                                                                                                                                           predis/src/Command/Traits/Rev.php                                                                   0000644                 00000002065 15233650113 0012714 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits;

use Predis\Command\Command;
use UnexpectedValueException;

/**
 * @mixin Command
 */
trait Rev
{
    public function setArguments(array $arguments)
    {
        $argument = $arguments[static::$revArgumentPositionOffset];

        if (false === $argument) {
            parent::setArguments($arguments);

            return;
        }

        if (true === $argument) {
            $argument = 'REV';
        } else {
            throw new UnexpectedValueException('Wrong rev argument type');
        }

        $argumentsBefore = array_slice($arguments, 0, static::$revArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$revArgumentPositionOffset + 1);

        parent::setArguments(array_merge($argumentsBefore, [$argument], $argumentsAfter));
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Traits/By/ByLexByScore.php                                                       0000644                 00000002471 15233650113 0015045 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\By;

use Predis\Command\Command;
use UnexpectedValueException;

/**
 * @mixin Command
 */
trait ByLexByScore
{
    private static $argumentsEnum = [
        'bylex' => 'BYLEX',
        'byscore' => 'BYSCORE',
    ];

    public function setArguments(array $arguments)
    {
        $argument = $arguments[static::$byLexByScoreArgumentPositionOffset];

        if (false === $argument) {
            parent::setArguments($arguments);

            return;
        }

        if (is_string($argument) && in_array(strtoupper($argument), self::$argumentsEnum)) {
            $argument = self::$argumentsEnum[$argument];
        } else {
            throw new UnexpectedValueException('By argument accepts only "bylex" and "byscore" values');
        }

        $argumentsBefore = array_slice($arguments, 0, static::$byLexByScoreArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$byLexByScoreArgumentPositionOffset + 1);

        parent::setArguments(array_merge($argumentsBefore, [$argument], $argumentsAfter));
    }
}
                                                                                                                                                                                                       predis/src/Command/Traits/By/GeoBy.php                                                              0000644                 00000002444 15233650113 0013540 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\By;

use InvalidArgumentException;
use Predis\Command\Argument\Geospatial\ByInterface;

trait GeoBy
{
    public function setArguments(array $arguments)
    {
        $argumentPositionOffset = $this->getByArgumentPositionOffset($arguments);

        if (null === $argumentPositionOffset) {
            throw new InvalidArgumentException('Invalid BY argument value given');
        }

        $byArgumentObject = $arguments[$argumentPositionOffset];
        $argumentsBefore = array_slice($arguments, 0, $argumentPositionOffset);
        $argumentsAfter = array_slice($arguments, $argumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            $byArgumentObject->toArray(),
            $argumentsAfter
        ));
    }

    private function getByArgumentPositionOffset(array $arguments): ?int
    {
        foreach ($arguments as $i => $value) {
            if ($value instanceof ByInterface) {
                return $i;
            }
        }

        return null;
    }
}
                                                                                                                                                                                                                            predis/src/Command/Traits/By/ByArgument.php                                                         0000644                 00000002064 15233650113 0014606 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\By;

use Predis\Command\Command;

/**
 * @mixin Command
 */
trait ByArgument
{
    private $byModifier = 'BY';

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$byArgumentPositionOffset >= $argumentsLength || null === $arguments[static::$byArgumentPositionOffset]) {
            parent::setArguments($arguments);

            return;
        }

        $argument = $arguments[static::$byArgumentPositionOffset];
        $argumentsBefore = array_slice($arguments, 0, static::$byArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$byArgumentPositionOffset + 1);

        parent::setArguments(array_merge($argumentsBefore, [$this->byModifier, $argument], $argumentsAfter));
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                            predis/src/Command/Traits/Limit/Limit.php                                                           0000644                 00000002700 15233650113 0014310 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\Limit;

use Predis\Command\Command;
use UnexpectedValueException;

/**
 * @mixin Command
 */
trait Limit
{
    private static $limitModifier = 'LIMIT';

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);
        $argumentsBefore = array_slice($arguments, 0, static::$limitArgumentPositionOffset);

        if (
            static::$limitArgumentPositionOffset >= $argumentsLength
            || false === $arguments[static::$limitArgumentPositionOffset]
        ) {
            parent::setArguments($argumentsBefore);

            return;
        }

        $argument = $arguments[static::$limitArgumentPositionOffset];
        $argumentsAfter = array_slice($arguments, static::$limitArgumentPositionOffset + 1);

        if (true === $argument) {
            parent::setArguments(array_merge($argumentsBefore, [self::$limitModifier], $argumentsAfter));

            return;
        }

        if (!is_int($argument)) {
            throw new UnexpectedValueException('Wrong limit argument type');
        }

        parent::setArguments(array_merge($argumentsBefore, [self::$limitModifier], [$argument], $argumentsAfter));
    }
}
                                                                predis/src/Command/Traits/Limit/LimitObject.php                                                     0000644                 00000002375 15233650113 0015447 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\Limit;

use Predis\Command\Argument\Server\LimitInterface;

trait LimitObject
{
    public function setArguments(array $arguments)
    {
        $argumentPositionOffset = $this->getLimitArgumentPositionOffset($arguments);

        if (null === $argumentPositionOffset) {
            parent::setArguments($arguments);

            return;
        }

        $limitObject = $arguments[$argumentPositionOffset];
        $argumentsBefore = array_slice($arguments, 0, $argumentPositionOffset);
        $argumentsAfter = array_slice($arguments, $argumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            $limitObject->toArray(),
            $argumentsAfter
        ));
    }

    private function getLimitArgumentPositionOffset(array $arguments): ?int
    {
        foreach ($arguments as $i => $value) {
            if ($value instanceof LimitInterface) {
                return $i;
            }
        }

        return null;
    }
}
                                                                                                                                                                                                                                                                   predis/src/Command/Traits/Replace.php                                                               0000644                 00000001253 15233650113 0013531 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits;

use Predis\Command\Command;

/**
 * @mixin Command
 */
trait Replace
{
    public function setArguments(array $arguments)
    {
        $replace = array_pop($arguments);

        if (is_bool($replace) && $replace) {
            $arguments[] = 'REPLACE';
        } elseif (!is_bool($replace)) {
            $arguments[] = $replace;
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                                                                     predis/src/Command/Traits/With/WithHash.php                                                         0000644                 00000002334 15233650113 0014611 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\With;

use UnexpectedValueException;

trait WithHash
{
    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (
            static::$withHashArgumentPositionOffset >= $argumentsLength
            || false === $arguments[static::$withHashArgumentPositionOffset]
        ) {
            parent::setArguments($arguments);

            return;
        }

        $argument = $arguments[static::$withHashArgumentPositionOffset];

        if (true === $argument) {
            $argument = 'WITHHASH';
        } else {
            throw new UnexpectedValueException('Wrong WITHHASH argument type');
        }

        $argumentsBefore = array_slice($arguments, 0, static::$withHashArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$withHashArgumentPositionOffset + 1);

        parent::setArguments(array_merge($argumentsBefore, [$argument], $argumentsAfter));
    }
}
                                                                                                                                                                                                                                                                                                    predis/src/Command/Traits/With/WithCoord.php                                                        0000644                 00000002432 15233650113 0014773 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\With;

use Predis\Command\Command;
use UnexpectedValueException;

/**
 * @mixin Command
 */
trait WithCoord
{
    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (
            static::$withCoordArgumentPositionOffset >= $argumentsLength
            || false === $arguments[static::$withCoordArgumentPositionOffset]
        ) {
            parent::setArguments($arguments);

            return;
        }

        $argument = $arguments[static::$withCoordArgumentPositionOffset];

        if (true === $argument) {
            $argument = 'WITHCOORD';
        } else {
            throw new UnexpectedValueException('Wrong WITHCOORD argument type');
        }

        $argumentsBefore = array_slice($arguments, 0, static::$withCoordArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$withCoordArgumentPositionOffset + 1);

        parent::setArguments(array_merge($argumentsBefore, [$argument], $argumentsAfter));
    }
}
                                                                                                                                                                                                                                      predis/src/Command/Traits/With/WithScores.php                                                       0000644                 00000003205 15233650113 0015162 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\With;

use Predis\Command\Command;

/**
 * Handles last argument passed into command as WITHSCORES.
 *
 * @mixin Command
 */
trait WithScores
{
    public function setArguments(array $arguments)
    {
        $withScores = array_pop($arguments);

        if (is_bool($withScores) && $withScores) {
            $arguments[] = 'WITHSCORES';
        } elseif (!is_bool($withScores)) {
            $arguments[] = $withScores;
        }

        parent::setArguments($arguments);
    }

    /**
     * Checks for the presence of the WITHSCORES modifier.
     *
     * @return bool
     */
    private function isWithScoreModifier(): bool
    {
        $arguments = parent::getArguments();
        $lastArgument = (!empty($arguments)) ? $arguments[count($arguments) - 1] : null;

        return is_string($lastArgument) && strtoupper($lastArgument) === 'WITHSCORES';
    }

    public function parseResponse($data)
    {
        if ($this->isWithScoreModifier()) {
            $result = [];

            for ($i = 0, $iMax = count($data); $i < $iMax; ++$i) {
                if (is_array($data[$i])) {
                    $result[$data[$i][0]] = $data[$i][1]; // Relay
                } elseif (array_key_exists($i + 1, $data)) {
                    $result[$data[$i]] = $data[++$i];
                }
            }

            return $result;
        }

        return $data;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                           predis/src/Command/Traits/With/WithValues.php                                                       0000644                 00000001305 15233650113 0015162 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\With;

use Predis\Command\Command;

/**
 * @mixin Command
 */
trait WithValues
{
    public function setArguments(array $arguments)
    {
        $withValues = array_pop($arguments);

        if (is_bool($withValues) && $withValues) {
            $arguments[] = 'WITHVALUES';
        } elseif (!is_bool($withValues)) {
            $arguments[] = $withValues;
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                                                                                                                                                                                                                           predis/src/Command/Traits/With/WithDist.php                                                         0000644                 00000002334 15233650113 0014631 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\With;

use UnexpectedValueException;

trait WithDist
{
    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (
            static::$withDistArgumentPositionOffset >= $argumentsLength
            || false === $arguments[static::$withDistArgumentPositionOffset]
        ) {
            parent::setArguments($arguments);

            return;
        }

        $argument = $arguments[static::$withDistArgumentPositionOffset];

        if (true === $argument) {
            $argument = 'WITHDIST';
        } else {
            throw new UnexpectedValueException('Wrong WITHDIST argument type');
        }

        $argumentsBefore = array_slice($arguments, 0, static::$withDistArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$withDistArgumentPositionOffset + 1);

        parent::setArguments(array_merge($argumentsBefore, [$argument], $argumentsAfter));
    }
}
                                                                                                                                                                                                                                                                                                    predis/src/Command/Traits/Keys.php                                                                  0000644                 00000002554 15233650113 0013076 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits;

use Predis\Command\Command;
use UnexpectedValueException;

/**
 * @mixin Command
 */
trait Keys
{
    public function setArguments(array $arguments, bool $withNumkeys = true)
    {
        $argumentsLength = count($arguments);

        if (
            static::$keysArgumentPositionOffset > $argumentsLength
            || !is_array($arguments[static::$keysArgumentPositionOffset])
        ) {
            throw new UnexpectedValueException('Wrong keys argument type or position offset');
        }

        $keysArgument = $arguments[static::$keysArgumentPositionOffset];
        $argumentsBeforeKeys = array_slice($arguments, 0, static::$keysArgumentPositionOffset);
        $argumentsAfterKeys = array_slice($arguments, static::$keysArgumentPositionOffset + 1);

        if ($withNumkeys) {
            $numkeys = count($keysArgument);
            parent::setArguments(array_merge($argumentsBeforeKeys, [$numkeys], $keysArgument, $argumentsAfterKeys));

            return;
        }

        parent::setArguments(array_merge($argumentsBeforeKeys, $keysArgument, $argumentsAfterKeys));
    }
}
                                                                                                                                                    predis/src/Command/Traits/Count.php                                                                 0000644                 00000003677 15233650113 0013262 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits;

use Predis\Command\Command;
use UnexpectedValueException;

/**
 * @mixin Command
 */
trait Count
{
    private $countModifier = 'COUNT';
    private $anyModifier = 'ANY';

    public function setArguments(array $arguments, bool $any = false)
    {
        $argumentsLength = count($arguments);

        if (static::$countArgumentPositionOffset >= $argumentsLength) {
            parent::setArguments($arguments);

            return;
        }

        if ($arguments[static::$countArgumentPositionOffset] === -1) {
            array_splice($arguments, static::$countArgumentPositionOffset, 1, [false]);
            parent::setArguments($arguments);

            return;
        }

        if ($arguments[static::$countArgumentPositionOffset] < 1) {
            throw new UnexpectedValueException('Wrong count argument value or position offset');
        }

        $countArgument = $arguments[static::$countArgumentPositionOffset];
        $argumentsBefore = array_slice($arguments, 0, static::$countArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$countArgumentPositionOffset + 2);

        if (!$any) {
            $argumentsAfter = array_slice($arguments, static::$countArgumentPositionOffset + 1);
            parent::setArguments(array_merge(
                $argumentsBefore,
                [$this->countModifier],
                [$countArgument],
                $argumentsAfter
            ));

            return;
        }

        parent::setArguments(array_merge(
            $argumentsBefore,
            [$this->countModifier],
            [$countArgument],
            [$this->anyModifier],
            $argumentsAfter
        ));
    }
}
                                                                 predis/src/Command/Traits/Json/Indent.php                                                           0000644                 00000002673 15233650113 0014317 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\Json;

use UnexpectedValueException;

trait Indent
{
    private static $indentModifier = 'INDENT';

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$indentArgumentPositionOffset >= $argumentsLength) {
            parent::setArguments($arguments);

            return;
        }

        if ($arguments[static::$indentArgumentPositionOffset] === '') {
            array_splice($arguments, static::$indentArgumentPositionOffset, 1, [false]);
            parent::setArguments($arguments);

            return;
        }

        $argument = $arguments[static::$indentArgumentPositionOffset];

        if (!is_string($argument)) {
            throw new UnexpectedValueException('Indent argument value should be a string');
        }

        $argumentsBefore = array_slice($arguments, 0, static::$indentArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$indentArgumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            [self::$indentModifier],
            [$argument],
            $argumentsAfter
        ));
    }
}
                                                                     predis/src/Command/Traits/Json/NxXxArgument.php                                                     0000644                 00000003252 15233650113 0015500 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\Json;

use Predis\Command\Command;
use UnexpectedValueException;

/**
 * @mixin Command
 */
trait NxXxArgument
{
    /**
     * @var string[]
     */
    private static $argumentEnum = [
        'nx' => 'NX',
        'xx' => 'XX',
    ];

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$nxXxArgumentPositionOffset >= $argumentsLength) {
            parent::setArguments($arguments);

            return;
        }

        if (null === $arguments[static::$nxXxArgumentPositionOffset]) {
            array_splice($arguments, static::$nxXxArgumentPositionOffset, 1, [false]);
            parent::setArguments($arguments);

            return;
        }

        $argument = $arguments[static::$nxXxArgumentPositionOffset];

        if (!in_array(strtoupper($argument), self::$argumentEnum, true)) {
            $enumValues = implode(', ', array_keys(self::$argumentEnum));
            throw new UnexpectedValueException("Argument accepts only: {$enumValues} values");
        }

        $argumentsBefore = array_slice($arguments, 0, static::$nxXxArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$nxXxArgumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            [self::$argumentEnum[strtolower($argument)]],
            $argumentsAfter
        ));
    }
}
                                                                                                                                                                                                                                                                                                                                                      predis/src/Command/Traits/Json/Space.php                                                            0000644                 00000002660 15233650113 0014125 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\Json;

use UnexpectedValueException;

trait Space
{
    private static $spaceModifier = 'SPACE';

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$spaceArgumentPositionOffset >= $argumentsLength) {
            parent::setArguments($arguments);

            return;
        }

        if ($arguments[static::$spaceArgumentPositionOffset] === '') {
            array_splice($arguments, static::$spaceArgumentPositionOffset, 1, [false]);
            parent::setArguments($arguments);

            return;
        }

        $argument = $arguments[static::$spaceArgumentPositionOffset];

        if (!is_string($argument)) {
            throw new UnexpectedValueException('Space argument value should be a string');
        }

        $argumentsBefore = array_slice($arguments, 0, static::$spaceArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$spaceArgumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            [self::$spaceModifier],
            [$argument],
            $argumentsAfter
        ));
    }
}
                                                                                predis/src/Command/Traits/Json/Newline.php                                                          0000644                 00000002706 15233650113 0014474 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\Json;

use UnexpectedValueException;

trait Newline
{
    private static $newlineModifier = 'NEWLINE';

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$newlineArgumentPositionOffset >= $argumentsLength) {
            parent::setArguments($arguments);

            return;
        }

        if ($arguments[static::$newlineArgumentPositionOffset] === '') {
            array_splice($arguments, static::$newlineArgumentPositionOffset, 1, [false]);
            parent::setArguments($arguments);

            return;
        }

        $argument = $arguments[static::$newlineArgumentPositionOffset];

        if (!is_string($argument)) {
            throw new UnexpectedValueException('Newline argument value should be a string');
        }

        $argumentsBefore = array_slice($arguments, 0, static::$newlineArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$newlineArgumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            [self::$newlineModifier],
            [$argument],
            $argumentsAfter
        ));
    }
}
                                                          predis/src/Command/Traits/LeftRight.php                                                             0000644                 00000003121 15233650113 0014042 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits;

use Predis\Command\Command;
use UnexpectedValueException;

/**
 * @mixin Command
 */
trait LeftRight
{
    /**
     * @var array{string: string}
     */
    private static $leftRightEnum = [
        'left' => 'LEFT',
        'right' => 'RIGHT',
    ];

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$leftRightArgumentPositionOffset >= $argumentsLength) {
            $arguments[] = 'LEFT';
            parent::setArguments($arguments);

            return;
        }

        $argument = $arguments[static::$leftRightArgumentPositionOffset];

        if (is_string($argument) && in_array(strtoupper($argument), self::$leftRightEnum, true)) {
            $argument = self::$leftRightEnum[$argument];
        } else {
            $enumValues = implode(', ', array_keys(self::$leftRightEnum));
            throw new UnexpectedValueException("Left/Right argument accepts only: {$enumValues} values");
        }

        $argumentsBefore = array_slice($arguments, 0, static::$leftRightArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$leftRightArgumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            [$argument],
            $argumentsAfter
        ));
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                               predis/src/Command/Traits/DB.php                                                                    0000644                 00000002642 15233650113 0012446 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits;

use UnexpectedValueException;

trait DB
{
    private $dbModifier = 'DB';

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$dbArgumentPositionOffset >= $argumentsLength) {
            parent::setArguments($arguments);

            return;
        }

        if (!is_numeric($arguments[static::$dbArgumentPositionOffset])) {
            throw new UnexpectedValueException('DB argument should be a valid numeric value');
        }

        if ($arguments[static::$dbArgumentPositionOffset] < 0) {
            array_splice($arguments, static::$dbArgumentPositionOffset, 1);
            parent::setArguments($arguments);

            return;
        }

        $argument = $arguments[static::$dbArgumentPositionOffset];
        $argumentsBefore = array_slice($arguments, 0, static::$dbArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$dbArgumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            [$this->dbModifier],
            [$argument],
            $argumentsAfter
        ));
    }
}
                                                                                              predis/src/Command/Traits/From/GeoFrom.php                                                          0000644                 00000002466 15233650113 0014426 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\From;

use InvalidArgumentException;
use Predis\Command\Argument\Geospatial\FromInterface;

trait GeoFrom
{
    public function setArguments(array $arguments)
    {
        $argumentPositionOffset = $this->getFromArgumentPositionOffset($arguments);

        if (null === $argumentPositionOffset) {
            throw new InvalidArgumentException('Invalid FROM argument value given');
        }

        $fromArgumentObject = $arguments[$argumentPositionOffset];
        $argumentsBefore = array_slice($arguments, 0, $argumentPositionOffset);
        $argumentsAfter = array_slice($arguments, $argumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            $fromArgumentObject->toArray(),
            $argumentsAfter
        ));
    }

    private function getFromArgumentPositionOffset(array $arguments): ?int
    {
        foreach ($arguments as $i => $value) {
            if ($value instanceof FromInterface) {
                return $i;
            }
        }

        return null;
    }
}
                                                                                                                                                                                                          predis/src/Command/Traits/Expire/ExpireOptions.php                                                  0000644                 00000001620 15233650113 0016220 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits\Expire;

trait ExpireOptions
{
    private static $argumentEnum = [
        'nx' => 'NX',
        'xx' => 'XX',
        'gt' => 'GT',
        'lt' => 'LT',
    ];

    public function setArguments(array $arguments)
    {
        $value = array_pop($arguments);

        if (null === $value) {
            parent::setArguments($arguments);

            return;
        }

        if (in_array(strtoupper($value), self::$argumentEnum, true)) {
            $arguments[] = self::$argumentEnum[strtolower($value)];
        } else {
            $arguments[] = $value;
        }

        parent::setArguments($arguments);
    }
}
                                                                                                                predis/src/Command/Traits/Sorting.php                                                               0000644                 00000003035 15233650113 0013603 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command\Traits;

use UnexpectedValueException;

trait Sorting
{
    private static $sortingEnum = [
        'asc' => 'ASC',
        'desc' => 'DESC',
    ];

    public function setArguments(array $arguments)
    {
        $argumentsLength = count($arguments);

        if (static::$sortArgumentPositionOffset >= $argumentsLength) {
            parent::setArguments($arguments);

            return;
        }

        $argument = $arguments[static::$sortArgumentPositionOffset];

        if (null === $argument) {
            array_splice($arguments, static::$sortArgumentPositionOffset, 1, [false]);
            parent::setArguments($arguments);

            return;
        }

        if (!in_array(strtoupper($argument), self::$sortingEnum, true)) {
            $enumValues = implode(', ', array_keys(self::$sortingEnum));
            throw new UnexpectedValueException("Sorting argument accepts only: {$enumValues} values");
        }

        $argumentsBefore = array_slice($arguments, 0, static::$sortArgumentPositionOffset);
        $argumentsAfter = array_slice($arguments, static::$sortArgumentPositionOffset + 1);

        parent::setArguments(array_merge(
            $argumentsBefore,
            [self::$sortingEnum[$argument]],
            $argumentsAfter
        ));
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   predis/src/Command/CommandInterface.php                                                             0000644                 00000003451 15233650113 0014111 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command;

/**
 * Defines an abstraction representing a Redis command.
 */
interface CommandInterface
{
    /**
     * Returns the ID of the Redis command. By convention, command identifiers
     * must always be uppercase.
     *
     * @return string
     */
    public function getId();

    /**
     * Assign the specified slot to the command for clustering distribution.
     *
     * @param int $slot Slot ID.
     */
    public function setSlot($slot);

    /**
     * Returns the assigned slot of the command for clustering distribution.
     *
     * @return int|null
     */
    public function getSlot();

    /**
     * Sets the arguments for the command.
     *
     * @param array $arguments List of arguments.
     */
    public function setArguments(array $arguments);

    /**
     * Sets the raw arguments for the command without processing them.
     *
     * @param array $arguments List of arguments.
     */
    public function setRawArguments(array $arguments);

    /**
     * Gets the arguments of the command.
     *
     * @return array
     */
    public function getArguments();

    /**
     * Gets the argument of the command at the specified index.
     *
     * @param int $index Index of the desired argument.
     *
     * @return mixed|null
     */
    public function getArgument($index);

    /**
     * Parses a raw response and returns a PHP object.
     *
     * @param string|array|null $data Binary string containing the whole response.
     *
     * @return mixed
     */
    public function parseResponse($data);
}
                                                                                                                                                                                                                       predis/src/Command/Factory.php                                                                      0000644                 00000010062 15233650113 0012315 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Command;

use InvalidArgumentException;
use Predis\ClientException;
use Predis\Command\Processor\ProcessorInterface;

/**
 * Base command factory class.
 *
 * This class provides all of the common functionalities required for a command
 * factory to create new instances of Redis commands objects. It also allows to
 * define or undefine command handler classes for each command ID.
 */
abstract class Factory implements FactoryInterface
{
    protected $commands = [];
    protected $processor;

    /**
     * {@inheritdoc}
     */
    public function supports(string ...$commandIDs): bool
    {
        foreach ($commandIDs as $commandID) {
            if ($this->getCommandClass($commandID) === null) {
                return false;
            }
        }

        return true;
    }

    /**
     * Returns the FQCN of a class that represents the specified command ID.
     *
     * @codeCoverageIgnore
     *
     * @param string $commandID Command ID
     *
     * @return string|null
     */
    public function getCommandClass(string $commandID): ?string
    {
        return $this->commands[strtoupper($commandID)] ?? null;
    }

    /**
     * {@inheritdoc}
     */
    public function create(string $commandID, array $arguments = []): CommandInterface
    {
        if (!$commandClass = $this->getCommandClass($commandID)) {
            $commandID = strtoupper($commandID);

            throw new ClientException("Command `$commandID` is not a registered Redis command.");
        }

        $command = new $commandClass();
        $command->setArguments($arguments);

        if (isset($this->processor)) {
            $this->processor->process($command);
        }

        return $command;
    }

    /**
     * Defines a command in the factory.
     *
     * Only classes implementing Predis\Command\CommandInterface are allowed to
     * handle a command. If the command specified by its ID is already handled
     * by the factory, the underlying command class is replaced by the new one.
     *
     * @param string $commandID    Command ID
     * @param string $commandClass FQCN of a class implementing Predis\Command\CommandInterface
     *
     * @throws InvalidArgumentException
     */
    public function define(string $commandID, string $commandClass): void
    {
        if (!is_a($commandClass, 'Predis\Command\CommandInterface', true)) {
            throw new InvalidArgumentException(
                "Class $commandClass must implement Predis\Command\CommandInterface"
            );
        }

        $this->commands[strtoupper($commandID)] = $commandClass;
    }

    /**
     * Undefines a command in the factory.
     *
     * When the factory already has a class handler associated to the specified
     * command ID it is removed from the map of known commands. Nothing happens
     * when the command is not handled by the factory.
     *
     * @param string $commandID Command ID
     */
    public function undefine(string $commandID): void
    {
        unset($this->commands[strtoupper($commandID)]);
    }

    /**
     * Sets a command processor for processing command arguments.
     *
     * Command processors are used to process and transform arguments of Redis
     * commands before their newly created instances are returned to the caller
     * of "create()".
     *
     * A NULL value can be used to effectively unset any processor if previously
     * set for the command factory.
     *
     * @param ProcessorInterface|null $processor Command processor or NULL value.
     */
    public function setProcessor(?ProcessorInterface $processor): void
    {
        $this->processor = $processor;
    }

    /**
     * Returns the current command processor.
     *
     * @return ProcessorInterface|null
     */
    public function getProcessor(): ?ProcessorInterface
    {
        return $this->processor;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                              predis/src/Collection/Iterator/Keyspace.php                                                         0000644                 00000001727 15233650113 0014770 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Collection\Iterator;

use Predis\ClientInterface;

/**
 * Abstracts the iteration of the keyspace on a Redis instance by leveraging the
 * SCAN command (Redis >= 2.8) wrapped in a fully-rewindable PHP iterator.
 *
 * @see http://redis.io/commands/scan
 */
class Keyspace extends CursorBasedIterator
{
    /**
     * {@inheritdoc}
     */
    public function __construct(ClientInterface $client, $match = null, $count = null)
    {
        $this->requiredCommand($client, 'SCAN');

        parent::__construct($client, $match, $count);
    }

    /**
     * {@inheritdoc}
     */
    protected function executeCommand()
    {
        return $this->client->scan($this->cursor, $this->getScanOptions());
    }
}
                                         predis/src/Collection/Iterator/CursorBasedIterator.php                                              0000644                 00000011140 15233650113 0017140 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Collection\Iterator;

use Iterator;
use Predis\ClientInterface;
use Predis\NotSupportedException;
use ReturnTypeWillChange;

/**
 * Provides the base implementation for a fully-rewindable PHP iterator that can
 * incrementally iterate over cursor-based collections stored on Redis using the
 * commands in the `SCAN` family.
 *
 * Given their incremental nature with multiple fetches, these kind of iterators
 * offer limited guarantees about the returned elements because the collection
 * can change several times during the iteration process.
 *
 * @see http://redis.io/commands/scan
 */
abstract class CursorBasedIterator implements Iterator
{
    protected $client;
    protected $match;
    protected $count;

    protected $valid;
    protected $fetchmore;
    protected $elements;
    protected $cursor;
    protected $position;
    protected $current;

    /**
     * @param ClientInterface $client Client connected to Redis.
     * @param string          $match  Pattern to match during the server-side iteration.
     * @param int             $count  Hint used by Redis to compute the number of results per iteration.
     */
    public function __construct(ClientInterface $client, $match = null, $count = null)
    {
        $this->client = $client;
        $this->match = $match;
        $this->count = $count;

        $this->reset();
    }

    /**
     * Ensures that the client supports the specified Redis command required to
     * fetch elements from the server to perform the iteration.
     *
     * @param ClientInterface $client    Client connected to Redis.
     * @param string          $commandID Command ID.
     *
     * @throws NotSupportedException
     */
    protected function requiredCommand(ClientInterface $client, $commandID)
    {
        if (!$client->getCommandFactory()->supports($commandID)) {
            throw new NotSupportedException("'$commandID' is not supported by the current command factory.");
        }
    }

    /**
     * Resets the inner state of the iterator.
     */
    protected function reset()
    {
        $this->valid = true;
        $this->fetchmore = true;
        $this->elements = [];
        $this->cursor = 0;
        $this->position = -1;
        $this->current = null;
    }

    /**
     * Returns an array of options for the `SCAN` command.
     *
     * @return array
     */
    protected function getScanOptions()
    {
        $options = [];

        if (strlen(strval($this->match)) > 0) {
            $options['MATCH'] = $this->match;
        }

        if ($this->count > 0) {
            $options['COUNT'] = $this->count;
        }

        return $options;
    }

    /**
     * Fetches a new set of elements from the remote collection, effectively
     * advancing the iteration process.
     *
     * @return array
     */
    abstract protected function executeCommand();

    /**
     * Populates the local buffer of elements fetched from the server during
     * the iteration.
     */
    protected function fetch()
    {
        [$cursor, $elements] = $this->executeCommand();

        if (!$cursor) {
            $this->fetchmore = false;
        }

        $this->cursor = $cursor;
        $this->elements = $elements;
    }

    /**
     * Extracts next values for key() and current().
     */
    protected function extractNext()
    {
        ++$this->position;
        $this->current = array_shift($this->elements);
    }

    /**
     * @return void
     */
    #[ReturnTypeWillChange]
    public function rewind()
    {
        $this->reset();
        $this->next();
    }

    /**
     * @return mixed
     */
    #[ReturnTypeWillChange]
    public function current()
    {
        return $this->current;
    }

    /**
     * @return int|null
     */
    #[ReturnTypeWillChange]
    public function key()
    {
        return $this->position;
    }

    /**
     * @return void
     */
    #[ReturnTypeWillChange]
    public function next()
    {
        tryFetch:
            if (!$this->elements && $this->fetchmore) {
                $this->fetch();
            }

            if ($this->elements) {
                $this->extractNext();
            } elseif ($this->cursor) {
                goto tryFetch;
            } else {
                $this->valid = false;
            }
    }

    /**
     * @return bool
     */
    #[ReturnTypeWillChange]
    public function valid()
    {
        return $this->valid;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                predis/src/Collection/Iterator/SetKey.php                                                           0000644                 00000002022 15233650113 0014415 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Collection\Iterator;

use Predis\ClientInterface;

/**
 * Abstracts the iteration of members stored in a set by leveraging the SSCAN
 * command (Redis >= 2.8) wrapped in a fully-rewindable PHP iterator.
 *
 * @see http://redis.io/commands/scan
 */
class SetKey extends CursorBasedIterator
{
    protected $key;

    /**
     * {@inheritdoc}
     */
    public function __construct(ClientInterface $client, $key, $match = null, $count = null)
    {
        $this->requiredCommand($client, 'SSCAN');

        parent::__construct($client, $match, $count);

        $this->key = $key;
    }

    /**
     * {@inheritdoc}
     */
    protected function executeCommand()
    {
        return $this->client->sscan($this->key, $this->cursor, $this->getScanOptions());
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              predis/src/Collection/Iterator/SortedSetKey.php                                                     0000644                 00000002413 15233650113 0015602 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Collection\Iterator;

use Predis\ClientInterface;

/**
 * Abstracts the iteration of members stored in a sorted set by leveraging the
 * ZSCAN command (Redis >= 2.8) wrapped in a fully-rewindable PHP iterator.
 *
 * @see http://redis.io/commands/scan
 */
class SortedSetKey extends CursorBasedIterator
{
    protected $key;

    /**
     * {@inheritdoc}
     */
    public function __construct(ClientInterface $client, $key, $match = null, $count = null)
    {
        $this->requiredCommand($client, 'ZSCAN');

        parent::__construct($client, $match, $count);

        $this->key = $key;
    }

    /**
     * {@inheritdoc}
     */
    protected function executeCommand()
    {
        return $this->client->zscan($this->key, $this->cursor, $this->getScanOptions());
    }

    /**
     * {@inheritdoc}
     */
    protected function extractNext()
    {
        $this->position = key($this->elements);
        $this->current = current($this->elements);

        unset($this->elements[$this->position]);
    }
}
                                                                                                                                                                                                                                                     predis/src/Collection/Iterator/ListKey.php                                                          0000644                 00000010741 15233650113 0014604 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Collection\Iterator;

use InvalidArgumentException;
use Iterator;
use Predis\ClientInterface;
use Predis\NotSupportedException;
use ReturnTypeWillChange;

/**
 * Abstracts the iteration of items stored in a list by leveraging the LRANGE
 * command wrapped in a fully-rewindable PHP iterator.
 *
 * This iterator tries to emulate the behaviour of cursor-based iterators based
 * on the SCAN-family of commands introduced in Redis <= 2.8, meaning that due
 * to its incremental nature with multiple fetches it can only offer limited
 * guarantees on the returned elements because the collection can change several
 * times (trimmed, deleted, overwritten) during the iteration process.
 *
 * @see http://redis.io/commands/lrange
 */
class ListKey implements Iterator
{
    protected $client;
    protected $count;
    protected $key;

    protected $valid;
    protected $fetchmore;
    protected $elements;
    protected $position;
    protected $current;

    /**
     * @param ClientInterface $client Client connected to Redis.
     * @param string          $key    Redis list key.
     * @param int             $count  Number of items retrieved on each fetch operation.
     *
     * @throws InvalidArgumentException
     */
    public function __construct(ClientInterface $client, $key, $count = 10)
    {
        $this->requiredCommand($client, 'LRANGE');

        if ((false === $count = filter_var($count, FILTER_VALIDATE_INT)) || $count < 0) {
            throw new InvalidArgumentException('The $count argument must be a positive integer.');
        }

        $this->client = $client;
        $this->key = $key;
        $this->count = $count;

        $this->reset();
    }

    /**
     * Ensures that the client instance supports the specified Redis command
     * required to fetch elements from the server to perform the iteration.
     *
     * @param ClientInterface $client    Client connected to Redis.
     * @param string          $commandID Command ID.
     *
     * @throws NotSupportedException
     */
    protected function requiredCommand(ClientInterface $client, $commandID)
    {
        if (!$client->getCommandFactory()->supports($commandID)) {
            throw new NotSupportedException("'$commandID' is not supported by the current command factory.");
        }
    }

    /**
     * Resets the inner state of the iterator.
     */
    protected function reset()
    {
        $this->valid = true;
        $this->fetchmore = true;
        $this->elements = [];
        $this->position = -1;
        $this->current = null;
    }

    /**
     * Fetches a new set of elements from the remote collection, effectively
     * advancing the iteration process.
     *
     * @return array
     */
    protected function executeCommand()
    {
        return $this->client->lrange($this->key, $this->position + 1, $this->position + $this->count);
    }

    /**
     * Populates the local buffer of elements fetched from the server during the
     * iteration.
     */
    protected function fetch()
    {
        $elements = $this->executeCommand();

        if (count($elements) < $this->count) {
            $this->fetchmore = false;
        }

        $this->elements = $elements;
    }

    /**
     * Extracts next values for key() and current().
     */
    protected function extractNext()
    {
        ++$this->position;
        $this->current = array_shift($this->elements);
    }

    /**
     * @return void
     */
    #[ReturnTypeWillChange]
    public function rewind()
    {
        $this->reset();
        $this->next();
    }

    /**
     * @return mixed
     */
    #[ReturnTypeWillChange]
    public function current()
    {
        return $this->current;
    }

    /**
     * @return int|null
     */
    #[ReturnTypeWillChange]
    public function key()
    {
        return $this->position;
    }

    /**
     * @return void
     */
    #[ReturnTypeWillChange]
    public function next()
    {
        if (!$this->elements && $this->fetchmore) {
            $this->fetch();
        }

        if ($this->elements) {
            $this->extractNext();
        } else {
            $this->valid = false;
        }
    }

    /**
     * @return bool
     */
    #[ReturnTypeWillChange]
    public function valid()
    {
        return $this->valid;
    }
}
                               predis/src/Collection/Iterator/HashKey.php                                                          0000644                 00000002404 15233650113 0014551 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Collection\Iterator;

use Predis\ClientInterface;

/**
 * Abstracts the iteration of fields and values of an hash by leveraging the
 * HSCAN command (Redis >= 2.8) wrapped in a fully-rewindable PHP iterator.
 *
 * @see http://redis.io/commands/scan
 */
class HashKey extends CursorBasedIterator
{
    protected $key;

    /**
     * {@inheritdoc}
     */
    public function __construct(ClientInterface $client, $key, $match = null, $count = null)
    {
        $this->requiredCommand($client, 'HSCAN');

        parent::__construct($client, $match, $count);

        $this->key = $key;
    }

    /**
     * {@inheritdoc}
     */
    protected function executeCommand()
    {
        return $this->client->hscan($this->key, $this->cursor, $this->getScanOptions());
    }

    /**
     * {@inheritdoc}
     */
    protected function extractNext()
    {
        $this->position = key($this->elements);
        $this->current = current($this->elements);

        unset($this->elements[$this->position]);
    }
}
                                                                                                                                                                                                                                                            predis/src/ClientException.php                                                                      0000644                 00000000605 15233650113 0012427 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis;

/**
 * Exception class that identifies client-side errors.
 */
class ClientException extends PredisException
{
}
                                                                                                                           predis/src/Connection/NodeConnectionInterface.php                                                   0000644                 00000002442 15233650113 0016160 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection;

use Predis\Command\CommandInterface;

/**
 * Defines a connection used to communicate with a single Redis node.
 */
interface NodeConnectionInterface extends ConnectionInterface
{
    /**
     * Returns a string representation of the connection.
     *
     * @return string
     */
    public function __toString();

    /**
     * Returns the underlying resource used to communicate with Redis.
     *
     * @return mixed
     */
    public function getResource();

    /**
     * Returns the parameters used to initialize the connection.
     *
     * @return ParametersInterface
     */
    public function getParameters();

    /**
     * Pushes the given command into a queue of commands executed when
     * establishing the actual connection to Redis.
     *
     * @param CommandInterface $command Instance of a Redis command.
     */
    public function addConnectCommand(CommandInterface $command);

    /**
     * Reads a response from the server.
     *
     * @return mixed
     */
    public function read();
}
                                                                                                                                                                                                                              predis/src/Connection/WebdisConnection.php                                                          0000644                 00000022211 15233650113 0014663 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection;

use Closure;
use InvalidArgumentException;
use Predis\Command\CommandInterface;
use Predis\NotSupportedException;
use Predis\Protocol\ProtocolException;
use Predis\Response\Error as ErrorResponse;
use Predis\Response\Status as StatusResponse;

/**
 * This class implements a Predis connection that actually talks with Webdis
 * instead of connecting directly to Redis. It relies on the cURL extension to
 * communicate with the web server and the phpiredis extension to parse the
 * protocol for responses returned in the http response bodies.
 *
 * Some features are not yet available or they simply cannot be implemented:
 *   - Pipelining commands.
 *   - Publish / Subscribe.
 *   - MULTI / EXEC transactions (not yet supported by Webdis).
 *
 * The connection parameters supported by this class are:
 *
 *  - scheme: must be 'http'.
 *  - host: hostname or IP address of the server.
 *  - port: TCP port of the server.
 *  - timeout: timeout to perform the connection (default is 5 seconds).
 *  - user: username for authentication.
 *  - pass: password for authentication.
 *
 * @see http://webd.is
 * @see http://github.com/nicolasff/webdis
 * @see http://github.com/seppo0010/phpiredis
 * @deprecated 2.1.2
 */
class WebdisConnection implements NodeConnectionInterface
{
    private $parameters;
    private $resource;
    private $reader;

    /**
     * @param ParametersInterface $parameters Initialization parameters for the connection.
     *
     * @throws InvalidArgumentException
     */
    public function __construct(ParametersInterface $parameters)
    {
        $this->assertExtensions();

        if ($parameters->scheme !== 'http') {
            throw new InvalidArgumentException("Invalid scheme: '{$parameters->scheme}'.");
        }

        $this->parameters = $parameters;

        $this->resource = $this->createCurl();
        $this->reader = $this->createReader();
    }

    /**
     * Frees the underlying cURL and protocol reader resources when the garbage
     * collector kicks in.
     */
    public function __destruct()
    {
        curl_close($this->resource);
        phpiredis_reader_destroy($this->reader);
    }

    /**
     * Helper method used to throw on unsupported methods.
     *
     * @param string $method Name of the unsupported method.
     *
     * @throws NotSupportedException
     */
    private function throwNotSupportedException($method)
    {
        $class = __CLASS__;
        throw new NotSupportedException("The method $class::$method() is not supported.");
    }

    /**
     * Checks if the cURL and phpiredis extensions are loaded in PHP.
     */
    private function assertExtensions()
    {
        if (!extension_loaded('curl')) {
            throw new NotSupportedException(
                'The "curl" extension is required by this connection backend.'
            );
        }

        if (!extension_loaded('phpiredis')) {
            throw new NotSupportedException(
                'The "phpiredis" extension is required by this connection backend.'
            );
        }
    }

    /**
     * Initializes cURL.
     *
     * @return resource
     */
    private function createCurl()
    {
        $parameters = $this->getParameters();
        $timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0) * 1000;

        if (filter_var($host = $parameters->host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
            $host = "[$host]";
        }

        $options = [
            CURLOPT_FAILONERROR => true,
            CURLOPT_CONNECTTIMEOUT_MS => $timeout,
            CURLOPT_URL => "$parameters->scheme://$host:$parameters->port",
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_POST => true,
            CURLOPT_WRITEFUNCTION => [$this, 'feedReader'],
        ];

        if (isset($parameters->user, $parameters->pass)) {
            $options[CURLOPT_USERPWD] = "{$parameters->user}:{$parameters->pass}";
        }

        curl_setopt_array($resource = curl_init(), $options);

        return $resource;
    }

    /**
     * Initializes the phpiredis protocol reader.
     *
     * @return resource
     */
    private function createReader()
    {
        $reader = phpiredis_reader_create();

        phpiredis_reader_set_status_handler($reader, $this->getStatusHandler());
        phpiredis_reader_set_error_handler($reader, $this->getErrorHandler());

        return $reader;
    }

    /**
     * Returns the handler used by the protocol reader for inline responses.
     *
     * @return Closure
     */
    protected function getStatusHandler()
    {
        static $statusHandler;

        if (!$statusHandler) {
            $statusHandler = function ($payload) {
                return StatusResponse::get($payload);
            };
        }

        return $statusHandler;
    }

    /**
     * Returns the handler used by the protocol reader for error responses.
     *
     * @return Closure
     */
    protected function getErrorHandler()
    {
        static $errorHandler;

        if (!$errorHandler) {
            $errorHandler = function ($errorMessage) {
                return new ErrorResponse($errorMessage);
            };
        }

        return $errorHandler;
    }

    /**
     * Feeds the phpredis reader resource with the data read from the network.
     *
     * @param resource $resource Reader resource.
     * @param string   $buffer   Buffer of data read from a connection.
     *
     * @return int
     */
    protected function feedReader($resource, $buffer)
    {
        phpiredis_reader_feed($this->reader, $buffer);

        return strlen($buffer);
    }

    /**
     * {@inheritdoc}
     */
    public function connect()
    {
        // NOOP
    }

    /**
     * {@inheritdoc}
     */
    public function disconnect()
    {
        // NOOP
    }

    /**
     * {@inheritdoc}
     */
    public function isConnected()
    {
        return true;
    }

    /**
     * Checks if the specified command is supported by this connection class.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return string
     * @throws NotSupportedException
     */
    protected function getCommandId(CommandInterface $command)
    {
        switch ($commandID = $command->getId()) {
            case 'AUTH':
            case 'SELECT':
            case 'MULTI':
            case 'EXEC':
            case 'WATCH':
            case 'UNWATCH':
            case 'DISCARD':
            case 'MONITOR':
                throw new NotSupportedException("Command '$commandID' is not allowed by Webdis.");
            default:
                return $commandID;
        }
    }

    /**
     * {@inheritdoc}
     */
    public function writeRequest(CommandInterface $command)
    {
        $this->throwNotSupportedException(__FUNCTION__);
    }

    /**
     * {@inheritdoc}
     */
    public function readResponse(CommandInterface $command)
    {
        $this->throwNotSupportedException(__FUNCTION__);
    }

    /**
     * {@inheritdoc}
     */
    public function executeCommand(CommandInterface $command)
    {
        $resource = $this->resource;
        $commandId = $this->getCommandId($command);

        if ($arguments = $command->getArguments()) {
            $arguments = implode('/', array_map('urlencode', $arguments));
            $serializedCommand = "$commandId/$arguments.raw";
        } else {
            $serializedCommand = "$commandId.raw";
        }

        curl_setopt($resource, CURLOPT_POSTFIELDS, $serializedCommand);

        if (curl_exec($resource) === false) {
            $error = trim(curl_error($resource));
            $errno = curl_errno($resource);

            throw new ConnectionException($this, "$error{$this->getParameters()}]", $errno);
        }

        if (phpiredis_reader_get_state($this->reader) !== PHPIREDIS_READER_STATE_COMPLETE) {
            throw new ProtocolException($this, phpiredis_reader_get_error($this->reader));
        }

        return phpiredis_reader_get_reply($this->reader);
    }

    /**
     * {@inheritdoc}
     */
    public function getResource()
    {
        return $this->resource;
    }

    /**
     * {@inheritdoc}
     */
    public function getParameters()
    {
        return $this->parameters;
    }

    /**
     * {@inheritdoc}
     */
    public function addConnectCommand(CommandInterface $command)
    {
        $this->throwNotSupportedException(__FUNCTION__);
    }

    /**
     * {@inheritdoc}
     */
    public function read()
    {
        $this->throwNotSupportedException(__FUNCTION__);
    }

    /**
     * {@inheritdoc}
     */
    public function __toString()
    {
        return "{$this->parameters->host}:{$this->parameters->port}";
    }

    /**
     * {@inheritdoc}
     */
    public function __sleep()
    {
        return ['parameters'];
    }

    /**
     * {@inheritdoc}
     */
    public function __wakeup()
    {
        $this->assertExtensions();

        $this->resource = $this->createCurl();
        $this->reader = $this->createReader();
    }
}
                                                                                                                                                                                                                                                                                                                                                                                       predis/src/Connection/Parameters.php                                                                0000644                 00000012266 15233650113 0013542 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection;

use InvalidArgumentException;

/**
 * Container for connection parameters used to initialize connections to Redis.
 *
 * {@inheritdoc}
 */
class Parameters implements ParametersInterface
{
    protected static $defaults = [
        'scheme' => 'tcp',
        'host' => '127.0.0.1',
        'port' => 6379,
    ];

    /**
     * Set of connection parameters already filtered
     * for NULL or 0-length string values.
     *
     * @var array
     */
    protected $parameters;

    /**
     * @param array $parameters Named array of connection parameters.
     */
    public function __construct(array $parameters = [])
    {
        $this->parameters = $this->filter($parameters + static::$defaults);
    }

    /**
     * Filters parameters removing entries with NULL or 0-length string values.
     *
     * @params array $parameters Array of parameters to be filtered
     *
     * @return array
     */
    protected function filter(array $parameters)
    {
        return array_filter($parameters, function ($value) {
            return $value !== null && $value !== '';
        });
    }

    /**
     * Creates a new instance by supplying the initial parameters either in the
     * form of an URI string or a named array.
     *
     * @param array|string $parameters Set of connection parameters.
     *
     * @return Parameters
     */
    public static function create($parameters)
    {
        if (is_string($parameters)) {
            $parameters = static::parse($parameters);
        }

        return new static($parameters ?: []);
    }

    /**
     * Parses an URI string returning an array of connection parameters.
     *
     * When using the "redis" and "rediss" schemes the URI is parsed according
     * to the rules defined by the provisional registration documents approved
     * by IANA. If the URI has a password in its "user-information" part or a
     * database number in the "path" part these values override the values of
     * "password" and "database" if they are present in the "query" part.
     *
     * @see http://www.iana.org/assignments/uri-schemes/prov/redis
     * @see http://www.iana.org/assignments/uri-schemes/prov/rediss
     *
     * @param string $uri URI string.
     *
     * @return array
     * @throws InvalidArgumentException
     */
    public static function parse($uri)
    {
        if (stripos($uri, 'unix://') === 0) {
            // parse_url() can parse unix:/path/to/sock so we do not need the
            // unix:///path/to/sock hack, we will support it anyway until 2.0.
            $uri = str_ireplace('unix://', 'unix:', $uri);
        }

        if (!$parsed = parse_url($uri)) {
            throw new InvalidArgumentException("Invalid parameters URI: $uri");
        }

        if (
            isset($parsed['host'])
            && false !== strpos($parsed['host'], '[')
            && false !== strpos($parsed['host'], ']')
        ) {
            $parsed['host'] = substr($parsed['host'], 1, -1);
        }

        if (isset($parsed['query'])) {
            parse_str($parsed['query'], $queryarray);
            unset($parsed['query']);

            $parsed = array_merge($parsed, $queryarray);
        }

        if (stripos($uri, 'redis') === 0) {
            if (isset($parsed['user'])) {
                if (strlen($parsed['user'])) {
                    $parsed['username'] = $parsed['user'];
                }
                unset($parsed['user']);
            }

            if (isset($parsed['pass'])) {
                if (strlen($parsed['pass'])) {
                    $parsed['password'] = $parsed['pass'];
                }
                unset($parsed['pass']);
            }

            if (isset($parsed['path']) && preg_match('/^\/(\d+)(\/.*)?/', $parsed['path'], $path)) {
                $parsed['database'] = $path[1];

                if (isset($path[2])) {
                    $parsed['path'] = $path[2];
                } else {
                    unset($parsed['path']);
                }
            }
        }

        return $parsed;
    }

    /**
     * {@inheritdoc}
     */
    public function toArray()
    {
        return $this->parameters;
    }

    /**
     * {@inheritdoc}
     */
    public function __get($parameter)
    {
        if (isset($this->parameters[$parameter])) {
            return $this->parameters[$parameter];
        }
    }

    /**
     * {@inheritdoc}
     */
    public function __isset($parameter)
    {
        return isset($this->parameters[$parameter]);
    }

    /**
     * {@inheritdoc}
     */
    public function __toString()
    {
        if ($this->scheme === 'unix') {
            return "$this->scheme:$this->path";
        }

        if (filter_var($this->host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
            return "$this->scheme://[$this->host]:$this->port";
        }

        return "$this->scheme://$this->host:$this->port";
    }

    /**
     * {@inheritdoc}
     */
    public function __sleep()
    {
        return ['parameters'];
    }
}
                                                                                                                                                                                                                                                                                                                                          predis/src/Connection/CompositeStreamConnection.php                                                 0000644                 00000005617 15233650113 0016577 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection;

use InvalidArgumentException;
use Predis\Command\CommandInterface;
use Predis\Protocol\ProtocolProcessorInterface;
use Predis\Protocol\Text\ProtocolProcessor as TextProtocolProcessor;

/**
 * Connection abstraction to Redis servers based on PHP's stream that uses an
 * external protocol processor defining the protocol used for the communication.
 */
class CompositeStreamConnection extends StreamConnection implements CompositeConnectionInterface
{
    protected $protocol;

    /**
     * @param ParametersInterface        $parameters Initialization parameters for the connection.
     * @param ProtocolProcessorInterface $protocol   Protocol processor.
     */
    public function __construct(
        ParametersInterface $parameters,
        ProtocolProcessorInterface $protocol = null
    ) {
        $this->parameters = $this->assertParameters($parameters);
        $this->protocol = $protocol ?: new TextProtocolProcessor();
    }

    /**
     * {@inheritdoc}
     */
    public function getProtocol()
    {
        return $this->protocol;
    }

    /**
     * {@inheritdoc}
     */
    public function writeBuffer($buffer)
    {
        $this->write($buffer);
    }

    /**
     * {@inheritdoc}
     */
    public function readBuffer($length)
    {
        if ($length <= 0) {
            throw new InvalidArgumentException('Length parameter must be greater than 0.');
        }

        $value = '';
        $socket = $this->getResource();

        do {
            $chunk = fread($socket, $length);

            if ($chunk === false || $chunk === '') {
                $this->onConnectionError('Error while reading bytes from the server.');
            }

            $value .= $chunk;
        } while (($length -= strlen($chunk)) > 0);

        return $value;
    }

    /**
     * {@inheritdoc}
     */
    public function readLine()
    {
        $value = '';
        $socket = $this->getResource();

        do {
            $chunk = fgets($socket);

            if ($chunk === false || $chunk === '') {
                $this->onConnectionError('Error while reading line from the server.');
            }

            $value .= $chunk;
        } while (substr($value, -2) !== "\r\n");

        return substr($value, 0, -2);
    }

    /**
     * {@inheritdoc}
     */
    public function writeRequest(CommandInterface $command)
    {
        $this->protocol->write($this, $command);
    }

    /**
     * {@inheritdoc}
     */
    public function read()
    {
        return $this->protocol->read($this);
    }

    /**
     * {@inheritdoc}
     */
    public function __sleep()
    {
        return array_merge(parent::__sleep(), ['protocol']);
    }
}
                                                                                                                 predis/src/Connection/ConnectionException.php                                                       0000644                 00000000706 15233650113 0015411 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection;

use Predis\CommunicationException;

/**
 * Exception class that identifies connection-related errors.
 */
class ConnectionException extends CommunicationException
{
}
                                                          predis/src/Connection/RelayMethods.php                                                              0000644                 00000006061 15233650113 0014033 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection;

trait RelayMethods
{
    /**
     * Registers a new `flushed` event listener.
     *
     * @param  callable $callback
     * @return bool
     */
    public function onFlushed(?callable $callback)
    {
        return $this->client->onFlushed($callback);
    }

    /**
     * Registers a new `invalidated` event listener.
     *
     * @param  callable $callback
     * @param  string   $pattern
     * @return bool
     */
    public function onInvalidated(?callable $callback, string $pattern = null)
    {
        return $this->client->onInvalidated($callback, $pattern);
    }

    /**
     * Dispatches all pending events.
     *
     * @return int|false
     */
    public function dispatchEvents()
    {
        return $this->client->dispatchEvents();
    }

    /**
     * Adds ignore pattern(s). Matching keys will not be cached in memory.
     *
     * @param  string $pattern,...
     * @return int
     */
    public function addIgnorePatterns(string ...$pattern)
    {
        return $this->client->addIgnorePatterns(...$pattern);
    }

    /**
     * Adds allow pattern(s). Only matching keys will be cached in memory.
     *
     * @param  string $pattern,...
     * @return int
     */
    public function addAllowPatterns(string ...$pattern)
    {
        return $this->client->addAllowPatterns(...$pattern);
    }

    /**
     * Returns the connection's endpoint identifier.
     *
     * @return string|false
     */
    public function endpointId()
    {
        return $this->client->endpointId();
    }

    /**
     * Returns a unique representation of the underlying socket connection identifier.
     *
     * @return string|false
     */
    public function socketId()
    {
        return $this->client->socketId();
    }

    /**
     * Returns information about the license.
     *
     * @return array<string, mixed>
     */
    public function license()
    {
        return $this->client->license();
    }

    /**
     * Returns statistics about Relay.
     *
     * @return array<string, array<string, mixed>>
     */
    public function stats()
    {
        return $this->client->stats();
    }

    /**
     * Returns the number of bytes allocated, or `0` in client-only mode.
     *
     * @return int
     */
    public function maxMemory()
    {
        return $this->client->maxMemory();
    }

    /**
     * Flushes Relay's in-memory cache of all databases.
     * When given an endpoint, only that connection will be flushed.
     * When given an endpoint and database index, only that database
     * for that connection will be flushed.
     *
     * @param  ?string $endpointId
     * @param  ?int    $db
     * @return bool
     */
    public function flushMemory(string $endpointId = null, int $db = null)
    {
        return $this->client->flushMemory($endpointId, $db);
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                               predis/src/Connection/Replication/SentinelReplication.php                                           0000644                 00000050734 15233650113 0017665 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection\Replication;

use InvalidArgumentException;
use Predis\Command\CommandInterface;
use Predis\Command\RawCommand;
use Predis\CommunicationException;
use Predis\Connection\ConnectionException;
use Predis\Connection\FactoryInterface as ConnectionFactoryInterface;
use Predis\Connection\NodeConnectionInterface;
use Predis\Connection\Parameters;
use Predis\Replication\ReplicationStrategy;
use Predis\Replication\RoleException;
use Predis\Response\Error;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\ServerException;

/**
 * @author Daniele Alessandri <suppakilla@gmail.com>
 * @author Ville Mattila <ville@eventio.fi>
 */
class SentinelReplication implements ReplicationInterface
{
    /**
     * @var NodeConnectionInterface
     */
    protected $master;

    /**
     * @var NodeConnectionInterface[]
     */
    protected $slaves = [];

    /**
     * @var NodeConnectionInterface[]
     */
    protected $pool = [];

    /**
     * @var NodeConnectionInterface
     */
    protected $current;

    /**
     * @var string
     */
    protected $service;

    /**
     * @var ConnectionFactoryInterface
     */
    protected $connectionFactory;

    /**
     * @var ReplicationStrategy
     */
    protected $strategy;

    /**
     * @var NodeConnectionInterface[]
     */
    protected $sentinels = [];

    /**
     * @var int
     */
    protected $sentinelIndex = 0;

    /**
     * @var NodeConnectionInterface
     */
    protected $sentinelConnection;

    /**
     * @var float
     */
    protected $sentinelTimeout = 0.100;

    /**
     * Max number of automatic retries of commands upon server failure.
     *
     * -1 = unlimited retry attempts
     *  0 = no retry attempts (fails immediately)
     *  n = fail only after n retry attempts
     *
     * @var int
     */
    protected $retryLimit = 20;

    /**
     * Time to wait in milliseconds before fetching a new configuration from one
     * of the sentinel servers.
     *
     * @var int
     */
    protected $retryWait = 1000;

    /**
     * Flag for automatic fetching of available sentinels.
     *
     * @var bool
     */
    protected $updateSentinels = false;

    /**
     * @param string                     $service           Name of the service for autodiscovery.
     * @param array                      $sentinels         Sentinel servers connection parameters.
     * @param ConnectionFactoryInterface $connectionFactory Connection factory instance.
     * @param ReplicationStrategy        $strategy          Replication strategy instance.
     */
    public function __construct(
        $service,
        array $sentinels,
        ConnectionFactoryInterface $connectionFactory,
        ReplicationStrategy $strategy = null
    ) {
        $this->sentinels = $sentinels;
        $this->service = $service;
        $this->connectionFactory = $connectionFactory;
        $this->strategy = $strategy ?: new ReplicationStrategy();
    }

    /**
     * Sets a default timeout for connections to sentinels.
     *
     * When "timeout" is present in the connection parameters of sentinels, its
     * value overrides the default sentinel timeout.
     *
     * @param float $timeout Timeout value.
     */
    public function setSentinelTimeout($timeout)
    {
        $this->sentinelTimeout = (float) $timeout;
    }

    /**
     * Sets the maximum number of retries for commands upon server failure.
     *
     * -1 = unlimited retry attempts
     *  0 = no retry attempts (fails immediately)
     *  n = fail only after n retry attempts
     *
     * @param int $retry Number of retry attempts.
     */
    public function setRetryLimit($retry)
    {
        $this->retryLimit = (int) $retry;
    }

    /**
     * Sets the time to wait (in milliseconds) before fetching a new configuration
     * from one of the sentinels.
     *
     * @param float $milliseconds Time to wait before the next attempt.
     */
    public function setRetryWait($milliseconds)
    {
        $this->retryWait = (float) $milliseconds;
    }

    /**
     * Set automatic fetching of available sentinels.
     *
     * @param bool $update Enable or disable automatic updates.
     */
    public function setUpdateSentinels($update)
    {
        $this->updateSentinels = (bool) $update;
    }

    /**
     * Resets the current connection.
     */
    protected function reset()
    {
        $this->current = null;
    }

    /**
     * Wipes the current list of master and slaves nodes.
     */
    protected function wipeServerList()
    {
        $this->reset();

        $this->master = null;
        $this->slaves = [];
        $this->pool = [];
    }

    /**
     * {@inheritdoc}
     */
    public function add(NodeConnectionInterface $connection)
    {
        $parameters = $connection->getParameters();
        $role = $parameters->role;

        if ('master' === $role) {
            $this->master = $connection;
        } elseif ('sentinel' === $role) {
            $this->sentinels[] = $connection;

            // sentinels are not considered part of the pool.
            return;
        } else {
            // everything else is considered a slave.
            $this->slaves[] = $connection;
        }

        $this->pool[(string) $connection] = $connection;

        $this->reset();
    }

    /**
     * {@inheritdoc}
     */
    public function remove(NodeConnectionInterface $connection)
    {
        if ($connection === $this->master) {
            $this->master = null;
        } elseif (false !== $id = array_search($connection, $this->slaves, true)) {
            unset($this->slaves[$id]);
        } elseif (false !== $id = array_search($connection, $this->sentinels, true)) {
            unset($this->sentinels[$id]);

            return true;
        } else {
            return false;
        }

        unset($this->pool[(string) $connection]);

        $this->reset();

        return true;
    }

    /**
     * Creates a new connection to a sentinel server.
     *
     * @return NodeConnectionInterface
     */
    protected function createSentinelConnection($parameters)
    {
        if ($parameters instanceof NodeConnectionInterface) {
            return $parameters;
        }

        if (is_string($parameters)) {
            $parameters = Parameters::parse($parameters);
        }

        if (is_array($parameters)) {
            // NOTE: sentinels do not accept AUTH and SELECT commands so we must
            // explicitly set them to NULL to avoid problems when using default
            // parameters set via client options. Actually AUTH is supported for
            // sentinels starting with Redis 5 but we have to differentiate from
            // sentinels passwords and nodes passwords, this will be implemented
            // in a later release.
            $parameters['database'] = null;
            $parameters['username'] = null;

            // don't leak password from between configurations
            // https://github.com/predis/predis/pull/807/#discussion_r985764770
            if (!isset($parameters['password'])) {
                $parameters['password'] = null;
            }

            if (!isset($parameters['timeout'])) {
                $parameters['timeout'] = $this->sentinelTimeout;
            }
        }

        return $this->connectionFactory->create($parameters);
    }

    /**
     * Returns the current sentinel connection.
     *
     * If there is no active sentinel connection, a new connection is created.
     *
     * @return NodeConnectionInterface
     */
    public function getSentinelConnection()
    {
        if (!$this->sentinelConnection) {
            if ($this->sentinelIndex >= count($this->sentinels)) {
                $this->sentinelIndex = 0;
                throw new \Predis\ClientException('No sentinel server available for autodiscovery.');
            }

            $sentinel = $this->sentinels[$this->sentinelIndex];
            ++$this->sentinelIndex;
            $this->sentinelConnection = $this->createSentinelConnection($sentinel);
        }

        return $this->sentinelConnection;
    }

    /**
     * Fetches an updated list of sentinels from a sentinel.
     */
    public function updateSentinels()
    {
        SENTINEL_QUERY: {
            $sentinel = $this->getSentinelConnection();

            try {
                $payload = $sentinel->executeCommand(
                    RawCommand::create('SENTINEL', 'sentinels', $this->service)
                );

                $this->sentinels = [];
                $this->sentinelIndex = 0;
                // NOTE: sentinel server does not return itself, so we add it back.
                $this->sentinels[] = $sentinel->getParameters()->toArray();

                foreach ($payload as $sentinel) {
                    $this->sentinels[] = [
                        'host' => $sentinel[3],
                        'port' => $sentinel[5],
                        'role' => 'sentinel',
                    ];
                }
            } catch (ConnectionException $exception) {
                $this->sentinelConnection = null;

                goto SENTINEL_QUERY;
            }
        }
    }

    /**
     * Fetches the details for the master and slave servers from a sentinel.
     */
    public function querySentinel()
    {
        $this->wipeServerList();

        $this->updateSentinels();
        $this->getMaster();
        $this->getSlaves();
    }

    /**
     * Handles error responses returned by redis-sentinel.
     *
     * @param NodeConnectionInterface $sentinel Connection to a sentinel server.
     * @param ErrorResponseInterface  $error    Error response.
     */
    private function handleSentinelErrorResponse(NodeConnectionInterface $sentinel, ErrorResponseInterface $error)
    {
        if ($error->getErrorType() === 'IDONTKNOW') {
            throw new ConnectionException($sentinel, $error->getMessage());
        } else {
            throw new ServerException($error->getMessage());
        }
    }

    /**
     * Fetches the details for the master server from a sentinel.
     *
     * @param NodeConnectionInterface $sentinel Connection to a sentinel server.
     * @param string                  $service  Name of the service.
     *
     * @return array
     */
    protected function querySentinelForMaster(NodeConnectionInterface $sentinel, $service)
    {
        $payload = $sentinel->executeCommand(
            RawCommand::create('SENTINEL', 'get-master-addr-by-name', $service)
        );

        if ($payload === null) {
            throw new ServerException('ERR No such master with that name');
        }

        if ($payload instanceof ErrorResponseInterface) {
            $this->handleSentinelErrorResponse($sentinel, $payload);
        }

        return [
            'host' => $payload[0],
            'port' => $payload[1],
            'role' => 'master',
        ];
    }

    /**
     * Fetches the details for the slave servers from a sentinel.
     *
     * @param NodeConnectionInterface $sentinel Connection to a sentinel server.
     * @param string                  $service  Name of the service.
     *
     * @return array
     */
    protected function querySentinelForSlaves(NodeConnectionInterface $sentinel, $service)
    {
        $slaves = [];

        $payload = $sentinel->executeCommand(
            RawCommand::create('SENTINEL', 'slaves', $service)
        );

        if ($payload instanceof ErrorResponseInterface) {
            $this->handleSentinelErrorResponse($sentinel, $payload);
        }

        foreach ($payload as $slave) {
            $flags = explode(',', $slave[9]);

            if (array_intersect($flags, ['s_down', 'o_down', 'disconnected'])) {
                continue;
            }

            $slaves[] = [
                'host' => $slave[3],
                'port' => $slave[5],
                'role' => 'slave',
            ];
        }

        return $slaves;
    }

    /**
     * {@inheritdoc}
     */
    public function getCurrent()
    {
        return $this->current;
    }

    /**
     * {@inheritdoc}
     */
    public function getMaster()
    {
        if ($this->master) {
            return $this->master;
        }

        if ($this->updateSentinels) {
            $this->updateSentinels();
        }

        SENTINEL_QUERY: {
            $sentinel = $this->getSentinelConnection();

            try {
                $masterParameters = $this->querySentinelForMaster($sentinel, $this->service);
                $masterConnection = $this->connectionFactory->create($masterParameters);

                $this->add($masterConnection);
            } catch (ConnectionException $exception) {
                $this->sentinelConnection = null;

                goto SENTINEL_QUERY;
            }
        }

        return $masterConnection;
    }

    /**
     * {@inheritdoc}
     */
    public function getSlaves()
    {
        if ($this->slaves) {
            return array_values($this->slaves);
        }

        if ($this->updateSentinels) {
            $this->updateSentinels();
        }

        SENTINEL_QUERY: {
            $sentinel = $this->getSentinelConnection();

            try {
                $slavesParameters = $this->querySentinelForSlaves($sentinel, $this->service);

                foreach ($slavesParameters as $slaveParameters) {
                    $this->add($this->connectionFactory->create($slaveParameters));
                }
            } catch (ConnectionException $exception) {
                $this->sentinelConnection = null;

                goto SENTINEL_QUERY;
            }
        }

        return array_values($this->slaves);
    }

    /**
     * Returns a random slave.
     *
     * @return NodeConnectionInterface|null
     */
    protected function pickSlave()
    {
        $slaves = $this->getSlaves();

        return $slaves
            ? $slaves[rand(1, count($slaves)) - 1]
            : null;
    }

    /**
     * Returns the connection instance in charge for the given command.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return NodeConnectionInterface
     */
    private function getConnectionInternal(CommandInterface $command)
    {
        if (!$this->current) {
            if ($this->strategy->isReadOperation($command) && $slave = $this->pickSlave()) {
                $this->current = $slave;
            } else {
                $this->current = $this->getMaster();
            }

            return $this->current;
        }

        if ($this->current === $this->master) {
            return $this->current;
        }

        if (!$this->strategy->isReadOperation($command)) {
            $this->current = $this->getMaster();
        }

        return $this->current;
    }

    /**
     * Asserts that the specified connection matches an expected role.
     *
     * @param NodeConnectionInterface $connection Connection to a redis server.
     * @param string                  $role       Expected role of the server ("master", "slave" or "sentinel").
     *
     * @throws RoleException|ConnectionException
     */
    protected function assertConnectionRole(NodeConnectionInterface $connection, $role)
    {
        $role = strtolower($role);
        $actualRole = $connection->executeCommand(RawCommand::create('ROLE'));

        if ($actualRole instanceof Error) {
            throw new ConnectionException($connection, $actualRole->getMessage());
        }

        if ($role !== $actualRole[0]) {
            throw new RoleException($connection, "Expected $role but got $actualRole[0] [$connection]");
        }
    }

    /**
     * {@inheritdoc}
     */
    public function getConnectionByCommand(CommandInterface $command)
    {
        $connection = $this->getConnectionInternal($command);

        if (!$connection->isConnected()) {
            // When we do not have any available slave in the pool we can expect
            // read-only operations to hit the master server.
            $expectedRole = $this->strategy->isReadOperation($command) && $this->slaves ? 'slave' : 'master';
            $this->assertConnectionRole($connection, $expectedRole);
        }

        return $connection;
    }

    /**
     * {@inheritdoc}
     */
    public function getConnectionById($id)
    {
        return $this->pool[$id] ?? null;
    }

    /**
     * Returns a connection by its role.
     *
     * @param string $role Connection role (`master`, `slave` or `sentinel`)
     *
     * @return NodeConnectionInterface|null
     */
    public function getConnectionByRole($role)
    {
        if ($role === 'master') {
            return $this->getMaster();
        } elseif ($role === 'slave') {
            return $this->pickSlave();
        } elseif ($role === 'sentinel') {
            return $this->getSentinelConnection();
        } else {
            return null;
        }
    }

    /**
     * Switches the internal connection in use by the backend.
     *
     * Sentinel connections are not considered as part of the pool, meaning that
     * trying to switch to a sentinel will throw an exception.
     *
     * @param NodeConnectionInterface $connection Connection instance in the pool.
     */
    public function switchTo(NodeConnectionInterface $connection)
    {
        if ($connection && $connection === $this->current) {
            return;
        }

        if ($connection !== $this->master && !in_array($connection, $this->slaves, true)) {
            throw new InvalidArgumentException('Invalid connection or connection not found.');
        }

        $connection->connect();

        if ($this->current) {
            $this->current->disconnect();
        }

        $this->current = $connection;
    }

    /**
     * {@inheritdoc}
     */
    public function switchToMaster()
    {
        $connection = $this->getConnectionByRole('master');
        $this->switchTo($connection);
    }

    /**
     * {@inheritdoc}
     */
    public function switchToSlave()
    {
        $connection = $this->getConnectionByRole('slave');
        $this->switchTo($connection);
    }

    /**
     * {@inheritdoc}
     */
    public function isConnected()
    {
        return $this->current ? $this->current->isConnected() : false;
    }

    /**
     * {@inheritdoc}
     */
    public function connect()
    {
        if (!$this->current) {
            if (!$this->current = $this->pickSlave()) {
                $this->current = $this->getMaster();
            }
        }

        $this->current->connect();
    }

    /**
     * {@inheritdoc}
     */
    public function disconnect()
    {
        foreach ($this->pool as $connection) {
            $connection->disconnect();
        }
    }

    /**
     * Retries the execution of a command upon server failure after asking a new
     * configuration to one of the sentinels.
     *
     * @param CommandInterface $command Command instance.
     * @param string           $method  Actual method.
     *
     * @return mixed
     */
    private function retryCommandOnFailure(CommandInterface $command, $method)
    {
        $retries = 0;

        while ($retries <= $this->retryLimit) {
            try {
                $response = $this->getConnectionByCommand($command)->$method($command);
                break;
            } catch (CommunicationException $exception) {
                $this->wipeServerList();
                $exception->getConnection()->disconnect();

                if ($retries === $this->retryLimit) {
                    throw $exception;
                }

                usleep($this->retryWait * 1000);

                ++$retries;
            }
        }

        return $response;
    }

    /**
     * {@inheritdoc}
     */
    public function writeRequest(CommandInterface $command)
    {
        $this->retryCommandOnFailure($command, __FUNCTION__);
    }

    /**
     * {@inheritdoc}
     */
    public function readResponse(CommandInterface $command)
    {
        return $this->retryCommandOnFailure($command, __FUNCTION__);
    }

    /**
     * {@inheritdoc}
     */
    public function executeCommand(CommandInterface $command)
    {
        return $this->retryCommandOnFailure($command, __FUNCTION__);
    }

    /**
     * Returns the underlying replication strategy.
     *
     * @return ReplicationStrategy
     */
    public function getReplicationStrategy()
    {
        return $this->strategy;
    }

    /**
     * {@inheritdoc}
     */
    public function __sleep()
    {
        return [
            'master', 'slaves', 'pool', 'service', 'sentinels', 'connectionFactory', 'strategy',
        ];
    }
}
                                    predis/src/Connection/Replication/ReplicationInterface.php                                          0000644                 00000002361 15233650113 0017775 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection\Replication;

use Predis\Connection\AggregateConnectionInterface;
use Predis\Connection\NodeConnectionInterface;

/**
 * Defines a group of Redis nodes in a master / slave replication setup.
 */
interface ReplicationInterface extends AggregateConnectionInterface
{
    /**
     * Switches the internal connection in use to the master server.
     */
    public function switchToMaster();

    /**
     * Switches the internal connection in use to a random slave server.
     */
    public function switchToSlave();

    /**
     * Returns the connection in use by the replication backend.
     *
     * @return NodeConnectionInterface
     */
    public function getCurrent();

    /**
     * Returns the connection to the master server.
     *
     * @return NodeConnectionInterface
     */
    public function getMaster();

    /**
     * Returns a list of connections to slave servers.
     *
     * @return NodeConnectionInterface[]
     */
    public function getSlaves();
}
                                                                                                                                                                                                                                                                               predis/src/Connection/Replication/MasterSlaveReplication.php                                        0000644                 00000034625 15233650113 0020333 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection\Replication;

use InvalidArgumentException;
use Predis\ClientException;
use Predis\Command\CommandInterface;
use Predis\Command\RawCommand;
use Predis\Connection\ConnectionException;
use Predis\Connection\FactoryInterface;
use Predis\Connection\NodeConnectionInterface;
use Predis\Replication\MissingMasterException;
use Predis\Replication\ReplicationStrategy;
use Predis\Response\ErrorInterface as ResponseErrorInterface;

/**
 * Aggregate connection handling replication of Redis nodes configured in a
 * single master / multiple slaves setup.
 */
class MasterSlaveReplication implements ReplicationInterface
{
    /**
     * @var ReplicationStrategy
     */
    protected $strategy;

    /**
     * @var NodeConnectionInterface
     */
    protected $master;

    /**
     * @var NodeConnectionInterface[]
     */
    protected $slaves = [];

    /**
     * @var NodeConnectionInterface[]
     */
    protected $pool = [];

    /**
     * @var NodeConnectionInterface[]
     */
    protected $aliases = [];

    /**
     * @var NodeConnectionInterface
     */
    protected $current;

    /**
     * @var bool
     */
    protected $autoDiscovery = false;

    /**
     * @var FactoryInterface
     */
    protected $connectionFactory;

    /**
     * {@inheritdoc}
     */
    public function __construct(ReplicationStrategy $strategy = null)
    {
        $this->strategy = $strategy ?: new ReplicationStrategy();
    }

    /**
     * Configures the automatic discovery of the replication configuration on failure.
     *
     * @param bool $value Enable or disable auto discovery.
     */
    public function setAutoDiscovery($value)
    {
        if (!$this->connectionFactory) {
            throw new ClientException('Automatic discovery requires a connection factory');
        }

        $this->autoDiscovery = (bool) $value;
    }

    /**
     * Sets the connection factory used to create the connections by the auto
     * discovery procedure.
     *
     * @param FactoryInterface $connectionFactory Connection factory instance.
     */
    public function setConnectionFactory(FactoryInterface $connectionFactory)
    {
        $this->connectionFactory = $connectionFactory;
    }

    /**
     * Resets the connection state.
     */
    protected function reset()
    {
        $this->current = null;
    }

    /**
     * {@inheritdoc}
     */
    public function add(NodeConnectionInterface $connection)
    {
        $parameters = $connection->getParameters();

        if ('master' === $parameters->role) {
            $this->master = $connection;
        } else {
            // everything else is considered a slvave.
            $this->slaves[] = $connection;
        }

        if (isset($parameters->alias)) {
            $this->aliases[$parameters->alias] = $connection;
        }

        $this->pool[(string) $connection] = $connection;

        $this->reset();
    }

    /**
     * {@inheritdoc}
     */
    public function remove(NodeConnectionInterface $connection)
    {
        if ($connection === $this->master) {
            $this->master = null;
        } elseif (false !== $id = array_search($connection, $this->slaves, true)) {
            unset($this->slaves[$id]);
        } else {
            return false;
        }

        unset($this->pool[(string) $connection]);

        if ($this->aliases && $alias = $connection->getParameters()->alias) {
            unset($this->aliases[$alias]);
        }

        $this->reset();

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function getConnectionByCommand(CommandInterface $command)
    {
        if (!$this->current) {
            if ($this->strategy->isReadOperation($command) && $slave = $this->pickSlave()) {
                $this->current = $slave;
            } else {
                $this->current = $this->getMasterOrDie();
            }

            return $this->current;
        }

        if ($this->current === $master = $this->getMasterOrDie()) {
            return $master;
        }

        if (!$this->strategy->isReadOperation($command) || !$this->slaves) {
            $this->current = $master;
        }

        return $this->current;
    }

    /**
     * {@inheritdoc}
     */
    public function getConnectionById($id)
    {
        return $this->pool[$id] ?? null;
    }

    /**
     * Returns a connection instance by its alias.
     *
     * @param string $alias Connection alias.
     *
     * @return NodeConnectionInterface|null
     */
    public function getConnectionByAlias($alias)
    {
        return $this->aliases[$alias] ?? null;
    }

    /**
     * Returns a connection by its role.
     *
     * @param string $role Connection role (`master` or `slave`)
     *
     * @return NodeConnectionInterface|null
     */
    public function getConnectionByRole($role)
    {
        if ($role === 'master') {
            return $this->getMaster();
        } elseif ($role === 'slave') {
            return $this->pickSlave();
        }

        return null;
    }

    /**
     * Switches the internal connection in use by the backend.
     *
     * @param NodeConnectionInterface $connection Connection instance in the pool.
     */
    public function switchTo(NodeConnectionInterface $connection)
    {
        if ($connection && $connection === $this->current) {
            return;
        }

        if ($connection !== $this->master && !in_array($connection, $this->slaves, true)) {
            throw new InvalidArgumentException('Invalid connection or connection not found.');
        }

        $this->current = $connection;
    }

    /**
     * {@inheritdoc}
     */
    public function switchToMaster()
    {
        if (!$connection = $this->getConnectionByRole('master')) {
            throw new InvalidArgumentException('Invalid connection or connection not found.');
        }

        $this->switchTo($connection);
    }

    /**
     * {@inheritdoc}
     */
    public function switchToSlave()
    {
        if (!$connection = $this->getConnectionByRole('slave')) {
            throw new InvalidArgumentException('Invalid connection or connection not found.');
        }

        $this->switchTo($connection);
    }

    /**
     * {@inheritdoc}
     */
    public function getCurrent()
    {
        return $this->current;
    }

    /**
     * {@inheritdoc}
     */
    public function getMaster()
    {
        return $this->master;
    }

    /**
     * Returns the connection associated to the master server.
     *
     * @return NodeConnectionInterface
     */
    private function getMasterOrDie()
    {
        if (!$connection = $this->getMaster()) {
            throw new MissingMasterException('No master server available for replication');
        }

        return $connection;
    }

    /**
     * {@inheritdoc}
     */
    public function getSlaves()
    {
        return $this->slaves;
    }

    /**
     * Returns the underlying replication strategy.
     *
     * @return ReplicationStrategy
     */
    public function getReplicationStrategy()
    {
        return $this->strategy;
    }

    /**
     * Returns a random slave.
     *
     * @return NodeConnectionInterface|null
     */
    protected function pickSlave()
    {
        if (!$this->slaves) {
            return null;
        }

        return $this->slaves[array_rand($this->slaves)];
    }

    /**
     * {@inheritdoc}
     */
    public function isConnected()
    {
        return $this->current ? $this->current->isConnected() : false;
    }

    /**
     * {@inheritdoc}
     */
    public function connect()
    {
        if (!$this->current) {
            if (!$this->current = $this->pickSlave()) {
                if (!$this->current = $this->getMaster()) {
                    throw new ClientException('No available connection for replication');
                }
            }
        }

        $this->current->connect();
    }

    /**
     * {@inheritdoc}
     */
    public function disconnect()
    {
        foreach ($this->pool as $connection) {
            $connection->disconnect();
        }
    }

    /**
     * Handles response from INFO.
     *
     * @param string $response
     *
     * @return array
     */
    private function handleInfoResponse($response)
    {
        $info = [];

        foreach (preg_split('/\r?\n/', $response) as $row) {
            if (strpos($row, ':') === false) {
                continue;
            }

            [$k, $v] = explode(':', $row, 2);
            $info[$k] = $v;
        }

        return $info;
    }

    /**
     * Fetches the replication configuration from one of the servers.
     */
    public function discover()
    {
        if (!$this->connectionFactory) {
            throw new ClientException('Discovery requires a connection factory');
        }

        while (true) {
            try {
                if ($connection = $this->getMaster()) {
                    $this->discoverFromMaster($connection, $this->connectionFactory);
                    break;
                } elseif ($connection = $this->pickSlave()) {
                    $this->discoverFromSlave($connection, $this->connectionFactory);
                    break;
                } else {
                    throw new ClientException('No connection available for discovery');
                }
            } catch (ConnectionException $exception) {
                $this->remove($connection);
            }
        }
    }

    /**
     * Discovers the replication configuration by contacting the master node.
     *
     * @param NodeConnectionInterface $connection        Connection to the master node.
     * @param FactoryInterface        $connectionFactory Connection factory instance.
     */
    protected function discoverFromMaster(NodeConnectionInterface $connection, FactoryInterface $connectionFactory)
    {
        $response = $connection->executeCommand(RawCommand::create('INFO', 'REPLICATION'));
        $replication = $this->handleInfoResponse($response);

        if ($replication['role'] !== 'master') {
            throw new ClientException("Role mismatch (expected master, got slave) [$connection]");
        }

        $this->slaves = [];

        foreach ($replication as $k => $v) {
            $parameters = null;

            if (strpos($k, 'slave') === 0 && preg_match('/ip=(?P<host>.*),port=(?P<port>\d+)/', $v, $parameters)) {
                $slaveConnection = $connectionFactory->create([
                    'host' => $parameters['host'],
                    'port' => $parameters['port'],
                    'role' => 'slave',
                ]);

                $this->add($slaveConnection);
            }
        }
    }

    /**
     * Discovers the replication configuration by contacting one of the slaves.
     *
     * @param NodeConnectionInterface $connection        Connection to one of the slaves.
     * @param FactoryInterface        $connectionFactory Connection factory instance.
     */
    protected function discoverFromSlave(NodeConnectionInterface $connection, FactoryInterface $connectionFactory)
    {
        $response = $connection->executeCommand(RawCommand::create('INFO', 'REPLICATION'));
        $replication = $this->handleInfoResponse($response);

        if ($replication['role'] !== 'slave') {
            throw new ClientException("Role mismatch (expected slave, got master) [$connection]");
        }

        $masterConnection = $connectionFactory->create([
            'host' => $replication['master_host'],
            'port' => $replication['master_port'],
            'role' => 'master',
        ]);

        $this->add($masterConnection);

        $this->discoverFromMaster($masterConnection, $connectionFactory);
    }

    /**
     * Retries the execution of a command upon slave failure.
     *
     * @param CommandInterface $command Command instance.
     * @param string           $method  Actual method.
     *
     * @return mixed
     */
    private function retryCommandOnFailure(CommandInterface $command, $method)
    {
        while (true) {
            try {
                $connection = $this->getConnectionByCommand($command);
                $response = $connection->$method($command);

                if ($response instanceof ResponseErrorInterface && $response->getErrorType() === 'LOADING') {
                    throw new ConnectionException($connection, "Redis is loading the dataset in memory [$connection]");
                }

                break;
            } catch (ConnectionException $exception) {
                $connection = $exception->getConnection();
                $connection->disconnect();

                if ($connection === $this->master && !$this->autoDiscovery) {
                    // Throw immediately when master connection is failing, even
                    // when the command represents a read-only operation, unless
                    // automatic discovery has been enabled.
                    throw $exception;
                } else {
                    // Otherwise remove the failing slave and attempt to execute
                    // the command again on one of the remaining slaves...
                    $this->remove($connection);
                }

                // ... that is, unless we have no more connections to use.
                if (!$this->slaves && !$this->master) {
                    throw $exception;
                } elseif ($this->autoDiscovery) {
                    $this->discover();
                }
            } catch (MissingMasterException $exception) {
                if ($this->autoDiscovery) {
                    $this->discover();
                } else {
                    throw $exception;
                }
            }
        }

        return $response;
    }

    /**
     * {@inheritdoc}
     */
    public function writeRequest(CommandInterface $command)
    {
        $this->retryCommandOnFailure($command, __FUNCTION__);
    }

    /**
     * {@inheritdoc}
     */
    public function readResponse(CommandInterface $command)
    {
        return $this->retryCommandOnFailure($command, __FUNCTION__);
    }

    /**
     * {@inheritdoc}
     */
    public function executeCommand(CommandInterface $command)
    {
        return $this->retryCommandOnFailure($command, __FUNCTION__);
    }

    /**
     * {@inheritdoc}
     */
    public function __sleep()
    {
        return ['master', 'slaves', 'pool', 'aliases', 'strategy'];
    }
}
                                                                                                           predis/src/Connection/AggregateConnectionInterface.php                                              0000644                 00000003044 15233650113 0017160 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection;

use Predis\Command\CommandInterface;

/**
 * Defines a virtual connection composed of multiple connection instances to
 * single Redis nodes.
 */
interface AggregateConnectionInterface extends ConnectionInterface
{
    /**
     * Adds a connection instance to the aggregate connection.
     *
     * @param NodeConnectionInterface $connection Connection instance.
     */
    public function add(NodeConnectionInterface $connection);

    /**
     * Removes the specified connection instance from the aggregate connection.
     *
     * @param NodeConnectionInterface $connection Connection instance.
     *
     * @return bool Returns true if the connection was in the pool.
     */
    public function remove(NodeConnectionInterface $connection);

    /**
     * Returns the connection instance in charge for the given command.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return NodeConnectionInterface
     */
    public function getConnectionByCommand(CommandInterface $command);

    /**
     * Returns a connection instance from the aggregate connection by its alias.
     *
     * @param string $connectionID Connection alias.
     *
     * @return NodeConnectionInterface|null
     */
    public function getConnectionById($connectionID);
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            predis/src/Connection/AbstractConnection.php                                                        0000644                 00000010715 15233650113 0015217 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection;

use InvalidArgumentException;
use Predis\Command\CommandInterface;
use Predis\Command\RawCommand;
use Predis\CommunicationException;
use Predis\Protocol\ProtocolException;

/**
 * Base class with the common logic used by connection classes to communicate
 * with Redis.
 */
abstract class AbstractConnection implements NodeConnectionInterface
{
    private $resource;
    private $cachedId;

    protected $parameters;

    /**
     * @var RawCommand[]
     */
    protected $initCommands = [];

    /**
     * @param ParametersInterface $parameters Initialization parameters for the connection.
     */
    public function __construct(ParametersInterface $parameters)
    {
        $this->parameters = $this->assertParameters($parameters);
    }

    /**
     * Disconnects from the server and destroys the underlying resource when
     * PHP's garbage collector kicks in.
     */
    public function __destruct()
    {
        $this->disconnect();
    }

    /**
     * Checks some of the parameters used to initialize the connection.
     *
     * @param ParametersInterface $parameters Initialization parameters for the connection.
     *
     * @return ParametersInterface
     * @throws InvalidArgumentException
     */
    abstract protected function assertParameters(ParametersInterface $parameters);

    /**
     * Creates the underlying resource used to communicate with Redis.
     *
     * @return mixed
     */
    abstract protected function createResource();

    /**
     * {@inheritdoc}
     */
    public function isConnected()
    {
        return isset($this->resource);
    }

    /**
     * {@inheritdoc}
     */
    public function connect()
    {
        if (!$this->isConnected()) {
            $this->resource = $this->createResource();

            return true;
        }

        return false;
    }

    /**
     * {@inheritdoc}
     */
    public function disconnect()
    {
        unset($this->resource);
    }

    /**
     * {@inheritdoc}
     */
    public function addConnectCommand(CommandInterface $command)
    {
        $this->initCommands[] = $command;
    }

    /**
     * {@inheritdoc}
     */
    public function getInitCommands(): array
    {
        return $this->initCommands;
    }

    /**
     * {@inheritdoc}
     */
    public function executeCommand(CommandInterface $command)
    {
        $this->writeRequest($command);

        return $this->readResponse($command);
    }

    /**
     * {@inheritdoc}
     */
    public function readResponse(CommandInterface $command)
    {
        return $this->read();
    }

    /**
     * Helper method to handle connection errors.
     *
     * @param string $message Error message.
     * @param int    $code    Error code.
     */
    protected function onConnectionError($message, $code = 0)
    {
        CommunicationException::handle(
            new ConnectionException($this, "$message [{$this->getParameters()}]", $code)
        );
    }

    /**
     * Helper method to handle protocol errors.
     *
     * @param string $message Error message.
     */
    protected function onProtocolError($message)
    {
        CommunicationException::handle(
            new ProtocolException($this, "$message [{$this->getParameters()}]")
        );
    }

    /**
     * {@inheritdoc}
     */
    public function getResource()
    {
        if (isset($this->resource)) {
            return $this->resource;
        }

        $this->connect();

        return $this->resource;
    }

    /**
     * {@inheritdoc}
     */
    public function getParameters()
    {
        return $this->parameters;
    }

    /**
     * Gets an identifier for the connection.
     *
     * @return string
     */
    protected function getIdentifier()
    {
        if ($this->parameters->scheme === 'unix') {
            return $this->parameters->path;
        }

        return "{$this->parameters->host}:{$this->parameters->port}";
    }

    /**
     * {@inheritdoc}
     */
    public function __toString()
    {
        if (!isset($this->cachedId)) {
            $this->cachedId = $this->getIdentifier();
        }

        return $this->cachedId;
    }

    /**
     * {@inheritdoc}
     */
    public function __sleep()
    {
        return ['parameters', 'initCommands'];
    }
}
                                                   predis/src/Connection/ParametersInterface.php                                                       0000644                 00000005132 15233650113 0015355 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection;

/**
 * Interface defining a container for connection parameters.
 *
 * The actual list of connection parameters depends on the features supported by
 * each connection backend class (please refer to their specific documentation),
 * but the most common parameters used through the library are:
 *
 * @property string $scheme             Connection scheme, such as 'tcp' or 'unix'.
 * @property string $host               IP address or hostname of Redis.
 * @property int    $port               TCP port on which Redis is listening to.
 * @property string $path               Path of a UNIX domain socket file.
 * @property string $alias              Alias for the connection.
 * @property float  $timeout            Timeout for the connect() operation.
 * @property float  $read_write_timeout Timeout for read() and write() operations.
 * @property bool   $persistent         Leaves the connection open after a GC collection.
 * @property string $password           Password to access Redis (see the AUTH command).
 * @property string $database           Database index (see the SELECT command).
 * @property bool   $async_connect      Performs the connect() operation asynchronously.
 * @property bool   $tcp_nodelay        Toggles the Nagle's algorithm for coalescing.
 * @property bool   $client_info        Whether to set LIB-NAME and LIB-VER when connecting.
 * @property bool   $cache              (Relay only) Whether to use in-memory caching.
 * @property string $serializer         (Relay only) Serializer used for data serialization.
 * @property string $compression        (Relay only) Algorithm used for data compression.
 */
interface ParametersInterface
{
    /**
     * Checks if the specified parameters is set.
     *
     * @param string $parameter Name of the parameter.
     *
     * @return bool
     */
    public function __isset($parameter);

    /**
     * Returns the value of the specified parameter.
     *
     * @param string $parameter Name of the parameter.
     *
     * @return mixed|null
     */
    public function __get($parameter);

    /**
     * Returns basic connection parameters as a valid URI string.
     *
     * @return string
     */
    public function __toString();

    /**
     * Returns an array representation of the connection parameters.
     *
     * @return array
     */
    public function toArray();
}
                                                                                                                                                                                                                                                                                                                                                                                                                                      predis/src/Connection/RelayConnection.php                                                           0000644                 00000021472 15233650113 0014532 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection;

use InvalidArgumentException;
use Predis\ClientException;
use Predis\Command\CommandInterface;
use Predis\NotSupportedException;
use Predis\Response\ServerException;
use Relay\Exception as RelayException;
use Relay\Relay;

/**
 * This class provides the implementation of a Predis connection that
 * uses Relay for network communication and in-memory caching.
 *
 * Using Relay allows for:
 * 1) significantly faster reads thanks to in-memory caching
 * 2) fast data serialization using igbinary
 * 3) fast data compression using lzf, lz4 or zstd
 *
 * Usage of igbinary serialization and zstd compresses reduces
 * network traffic and Redis memory usage by ~75%.
 *
 * For instructions on how to install the Relay extension, please consult
 * the repository of the project: https://relay.so/docs/installation
 *
 * The connection parameters supported by this class are:
 *
 *  - scheme: it can be either 'tcp', 'tls' or 'unix'.
 *  - host: hostname or IP address of the server.
 *  - port: TCP port of the server.
 *  - path: path of a UNIX domain socket when scheme is 'unix'.
 *  - timeout: timeout to perform the connection.
 *  - read_write_timeout: timeout of read / write operations.
 *  - cache: whether to use in-memory caching
 *  - serializer: data serializer
 *  - compression: data compression algorithm
 *
 * @see https://github.com/cachewerk/relay
 */
class RelayConnection extends StreamConnection
{
    use RelayMethods;

    /**
     * The Relay instance.
     *
     * @var \Relay\Relay
     */
    protected $client;

    /**
     * These commands must be called on the client, not using `Relay::rawCommand()`.
     *
     * @var string[]
     */
    public $atypicalCommands = [
        'AUTH',
        'SELECT',

        'TYPE',

        'MULTI',
        'EXEC',
        'DISCARD',

        'WATCH',
        'UNWATCH',

        'SUBSCRIBE',
        'UNSUBSCRIBE',
        'PSUBSCRIBE',
        'PUNSUBSCRIBE',
        'SSUBSCRIBE',
        'SUNSUBSCRIBE',
    ];

    /**
     * {@inheritdoc}
     */
    public function __construct(ParametersInterface $parameters)
    {
        $this->assertExtensions();

        $this->parameters = $this->assertParameters($parameters);
        $this->client = $this->createClient();
    }

    /**
     * {@inheritdoc}
     */
    public function isConnected()
    {
        return $this->client->isConnected();
    }

    /**
     * {@inheritdoc}
     */
    public function disconnect()
    {
        if ($this->client->isConnected()) {
            $this->client->close();
        }
    }

    /**
     * Checks if the Relay extension is loaded in PHP.
     */
    private function assertExtensions()
    {
        if (!extension_loaded('relay')) {
            throw new NotSupportedException(
                'The "relay" extension is required by this connection backend.'
            );
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function assertParameters(ParametersInterface $parameters)
    {
        if (!in_array($parameters->scheme, ['tcp', 'tls', 'unix', 'redis', 'rediss'])) {
            throw new InvalidArgumentException("Invalid scheme: '{$parameters->scheme}'.");
        }

        if (!in_array($parameters->serializer, [null, 'php', 'igbinary', 'msgpack', 'json'])) {
            throw new InvalidArgumentException("Invalid serializer: '{$parameters->serializer}'.");
        }

        if (!in_array($parameters->compression, [null, 'lzf', 'lz4', 'zstd'])) {
            throw new InvalidArgumentException("Invalid compression algorithm: '{$parameters->compression}'.");
        }

        return $parameters;
    }

    /**
     * Creates a new instance of the client.
     *
     * @return \Relay\Relay
     */
    private function createClient()
    {
        $client = new Relay();

        // throw when errors occur and return `null` for non-existent keys
        $client->setOption(Relay::OPT_PHPREDIS_COMPATIBILITY, false);

        // use reply literals
        $client->setOption(Relay::OPT_REPLY_LITERAL, true);

        // disable Relay's command/connection retry
        $client->setOption(Relay::OPT_MAX_RETRIES, 0);

        // whether to use in-memory caching
        $client->setOption(Relay::OPT_USE_CACHE, $this->parameters->cache ?? true);

        // set data serializer
        $client->setOption(Relay::OPT_SERIALIZER, constant(sprintf(
            '%s::SERIALIZER_%s',
            Relay::class,
            strtoupper($this->parameters->serializer ?? 'none')
        )));

        // set data compression algorithm
        $client->setOption(Relay::OPT_COMPRESSION, constant(sprintf(
            '%s::COMPRESSION_%s',
            Relay::class,
            strtoupper($this->parameters->compression ?? 'none')
        )));

        return $client;
    }

    /**
     * Returns the underlying client.
     *
     * @return \Relay\Relay
     */
    public function getClient()
    {
        return $this->client;
    }

    /**
     * {@inheritdoc}
     */
    protected function getIdentifier()
    {
        return $this->client->endpointId();
    }

    /**
     * {@inheritdoc}
     */
    protected function createStreamSocket(ParametersInterface $parameters, $address, $flags)
    {
        $timeout = isset($parameters->timeout) ? (float) $parameters->timeout : 5.0;

        $retry_interval = 0;
        $read_timeout = 5.0;

        if (isset($parameters->read_write_timeout)) {
            $read_timeout = (float) $parameters->read_write_timeout;
            $read_timeout = $read_timeout > 0 ? $read_timeout : 0;
        }

        try {
            $this->client->connect(
                $parameters->path ?? $parameters->host,
                isset($parameters->path) ? 0 : $parameters->port,
                $timeout,
                null,
                $retry_interval,
                $read_timeout
            );
        } catch (RelayException $ex) {
            $this->onConnectionError($ex->getMessage(), $ex->getCode());
        }

        return $this->client;
    }

    /**
     * {@inheritdoc}
     */
    public function executeCommand(CommandInterface $command)
    {
        if (!$this->client->isConnected()) {
            $this->getResource();
        }

        try {
            $name = $command->getId();

            // When using compression or a serializer, we'll need a dedicated
            // handler for `Predis\Command\RawCommand` calls, currently both
            // parameters are unsupported until a future Relay release
            return in_array($name, $this->atypicalCommands)
                ? $this->client->{$name}(...$command->getArguments())
                : $this->client->rawCommand($name, ...$command->getArguments());
        } catch (RelayException $ex) {
            throw $this->onCommandError($ex, $command);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function onCommandError(RelayException $exception, CommandInterface $command)
    {
        $code = $exception->getCode();
        $message = $exception->getMessage();

        if (strpos($message, 'RELAY_ERR_IO')) {
            return new ConnectionException($this, $message, $code, $exception);
        }

        if (strpos($message, 'RELAY_ERR_REDIS')) {
            return new ServerException($message, $code, $exception);
        }

        if (strpos($message, 'RELAY_ERR_WRONGTYPE') && strpos($message, "Got reply-type 'status'")) {
            $message = 'Operation against a key holding the wrong kind of value';
        }

        return new ClientException($message, $code, $exception);
    }

    /**
     * Applies the configured serializer and compression to given value.
     *
     * @param  mixed  $value
     * @return string
     */
    public function pack($value)
    {
        return $this->client->_pack($value);
    }

    /**
     * Deserializes and decompresses to given value.
     *
     * @param  mixed  $value
     * @return string
     */
    public function unpack($value)
    {
        return $this->client->_unpack($value);
    }

    /**
     * {@inheritdoc}
     */
    public function writeRequest(CommandInterface $command)
    {
        throw new NotSupportedException('The "relay" extension does not support writing requests.');
    }

    /**
     * {@inheritdoc}
     */
    public function readResponse(CommandInterface $command)
    {
        throw new NotSupportedException('The "relay" extension does not support reading responses.');
    }

    /**
     * {@inheritdoc}
     */
    public function __destruct()
    {
        $this->disconnect();
    }

    /**
     * {@inheritdoc}
     */
    public function __wakeup()
    {
        $this->assertExtensions();
        $this->client = $this->createClient();
    }
}
                                                                                                                                                                                                      predis/src/Connection/FactoryInterface.php                                                          0000644                 00000002153 15233650113 0014661 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection;

/**
 * Interface for classes providing a factory of connections to Redis nodes.
 */
interface FactoryInterface
{
    /**
     * Defines or overrides the connection class identified by a scheme prefix.
     *
     * @param string $scheme      Target connection scheme.
     * @param mixed  $initializer Fully-qualified name of a class or a callable for lazy initialization.
     */
    public function define($scheme, $initializer);

    /**
     * Undefines the connection identified by a scheme prefix.
     *
     * @param string $scheme Target connection scheme.
     */
    public function undefine($scheme);

    /**
     * Creates a new connection object.
     *
     * @param mixed $parameters Initialization parameters for the connection.
     *
     * @return NodeConnectionInterface
     */
    public function create($parameters);
}
                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Connection/PhpiredisStreamConnection.php                                                 0000644                 00000016470 15233650113 0016563 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection;

use Closure;
use InvalidArgumentException;
use Predis\Command\CommandInterface;
use Predis\NotSupportedException;
use Predis\Response\Error as ErrorResponse;
use Predis\Response\Status as StatusResponse;

/**
 * This class provides the implementation of a Predis connection that uses PHP's
 * streams for network communication and wraps the phpiredis C extension (PHP
 * bindings for hiredis) to parse and serialize the Redis protocol.
 *
 * This class is intended to provide an optional low-overhead alternative for
 * processing responses from Redis compared to the standard pure-PHP classes.
 * Differences in speed when dealing with short inline responses are practically
 * nonexistent, the actual speed boost is for big multibulk responses when this
 * protocol processor can parse and return responses very fast.
 *
 * For instructions on how to build and install the phpiredis extension, please
 * consult the repository of the project.
 *
 * The connection parameters supported by this class are:
 *
 *  - scheme: it can be either 'redis', 'tcp' or 'unix'.
 *  - host: hostname or IP address of the server.
 *  - port: TCP port of the server.
 *  - path: path of a UNIX domain socket when scheme is 'unix'.
 *  - timeout: timeout to perform the connection.
 *  - read_write_timeout: timeout of read / write operations.
 *  - async_connect: performs the connection asynchronously.
 *  - tcp_nodelay: enables or disables Nagle's algorithm for coalescing.
 *  - persistent: the connection is left intact after a GC collection.
 *
 * @see https://github.com/nrk/phpiredis
 * @deprecated 2.1.2
 */
class PhpiredisStreamConnection extends StreamConnection
{
    private $reader;

    /**
     * {@inheritdoc}
     */
    public function __construct(ParametersInterface $parameters)
    {
        $this->assertExtensions();

        parent::__construct($parameters);

        $this->reader = $this->createReader();
    }

    /**
     * {@inheritdoc}
     */
    public function __destruct()
    {
        parent::__destruct();

        phpiredis_reader_destroy($this->reader);
    }

    /**
     * {@inheritdoc}
     */
    public function disconnect()
    {
        phpiredis_reader_reset($this->reader);

        parent::disconnect();
    }

    /**
     * Checks if the phpiredis extension is loaded in PHP.
     */
    private function assertExtensions()
    {
        if (!extension_loaded('phpiredis')) {
            throw new NotSupportedException(
                'The "phpiredis" extension is required by this connection backend.'
            );
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function assertParameters(ParametersInterface $parameters)
    {
        switch ($parameters->scheme) {
            case 'tcp':
            case 'redis':
            case 'unix':
                break;

            case 'tls':
            case 'rediss':
                throw new InvalidArgumentException('SSL encryption is not supported by this connection backend.');
            default:
                throw new InvalidArgumentException("Invalid scheme: '$parameters->scheme'.");
        }

        return $parameters;
    }

    /**
     * {@inheritdoc}
     */
    protected function createStreamSocket(ParametersInterface $parameters, $address, $flags)
    {
        $socket = null;
        $timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0);
        $context = stream_context_create(['socket' => ['tcp_nodelay' => (bool) $parameters->tcp_nodelay]]);

        if (!$resource = @stream_socket_client($address, $errno, $errstr, $timeout, $flags, $context)) {
            $this->onConnectionError(trim($errstr), $errno);
        }

        if (isset($parameters->read_write_timeout) && function_exists('socket_import_stream')) {
            $rwtimeout = (float) $parameters->read_write_timeout;
            $rwtimeout = $rwtimeout > 0 ? $rwtimeout : -1;

            $timeout = [
                'sec' => $timeoutSeconds = floor($rwtimeout),
                'usec' => ($rwtimeout - $timeoutSeconds) * 1000000,
            ];

            $socket = $socket ?: socket_import_stream($resource);
            @socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, $timeout);
            @socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, $timeout);
        }

        if (isset($parameters->tcp_nodelay) && function_exists('socket_import_stream')) {
            $socket = $socket ?: socket_import_stream($resource);
            socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $parameters->tcp_nodelay);
        }

        return $resource;
    }

    /**
     * Creates a new instance of the protocol reader resource.
     *
     * @return resource
     */
    private function createReader()
    {
        $reader = phpiredis_reader_create();

        phpiredis_reader_set_status_handler($reader, $this->getStatusHandler());
        phpiredis_reader_set_error_handler($reader, $this->getErrorHandler());

        return $reader;
    }

    /**
     * Returns the underlying protocol reader resource.
     *
     * @return resource
     */
    protected function getReader()
    {
        return $this->reader;
    }

    /**
     * Returns the handler used by the protocol reader for inline responses.
     *
     * @return Closure
     */
    protected function getStatusHandler()
    {
        static $statusHandler;

        if (!$statusHandler) {
            $statusHandler = function ($payload) {
                return StatusResponse::get($payload);
            };
        }

        return $statusHandler;
    }

    /**
     * Returns the handler used by the protocol reader for error responses.
     *
     * @return Closure
     */
    protected function getErrorHandler()
    {
        static $errorHandler;

        if (!$errorHandler) {
            $errorHandler = function ($errorMessage) {
                return new ErrorResponse($errorMessage);
            };
        }

        return $errorHandler;
    }

    /**
     * {@inheritdoc}
     */
    public function read()
    {
        $socket = $this->getResource();
        $reader = $this->reader;

        while (PHPIREDIS_READER_STATE_INCOMPLETE === $state = phpiredis_reader_get_state($reader)) {
            $buffer = stream_socket_recvfrom($socket, 4096);

            if ($buffer === false || $buffer === '') {
                $this->onConnectionError('Error while reading bytes from the server.');
            }

            phpiredis_reader_feed($reader, $buffer);
        }

        if ($state === PHPIREDIS_READER_STATE_COMPLETE) {
            return phpiredis_reader_get_reply($reader);
        } else {
            $this->onProtocolError(phpiredis_reader_get_error($reader));

            return;
        }
    }

    /**
     * {@inheritdoc}
     */
    public function writeRequest(CommandInterface $command)
    {
        $arguments = $command->getArguments();
        array_unshift($arguments, $command->getId());

        $this->write(phpiredis_format_command($arguments));
    }

    /**
     * {@inheritdoc}
     */
    public function __wakeup()
    {
        $this->assertExtensions();
        $this->reader = $this->createReader();
    }
}
                                                                                                                                                                                                        predis/src/Connection/PhpiredisSocketConnection.php                                                 0000644                 00000027072 15233650113 0016560 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection;

use Closure;
use InvalidArgumentException;
use Predis\Command\CommandInterface;
use Predis\NotSupportedException;
use Predis\Response\Error as ErrorResponse;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\Status as StatusResponse;

/**
 * This class provides the implementation of a Predis connection that uses the
 * PHP socket extension for network communication and wraps the phpiredis C
 * extension (PHP bindings for hiredis) to parse the Redis protocol.
 *
 * This class is intended to provide an optional low-overhead alternative for
 * processing responses from Redis compared to the standard pure-PHP classes.
 * Differences in speed when dealing with short inline responses are practically
 * nonexistent, the actual speed boost is for big multibulk responses when this
 * protocol processor can parse and return responses very fast.
 *
 * For instructions on how to build and install the phpiredis extension, please
 * consult the repository of the project.
 *
 * The connection parameters supported by this class are:
 *
 *  - scheme: it can be either 'redis', 'tcp' or 'unix'.
 *  - host: hostname or IP address of the server.
 *  - port: TCP port of the server.
 *  - path: path of a UNIX domain socket when scheme is 'unix'.
 *  - timeout: timeout to perform the connection (default is 5 seconds).
 *  - read_write_timeout: timeout of read / write operations.
 *
 * @see http://github.com/nrk/phpiredis
 * @deprecated 2.1.2
 */
class PhpiredisSocketConnection extends AbstractConnection
{
    private $reader;

    /**
     * {@inheritdoc}
     */
    public function __construct(ParametersInterface $parameters)
    {
        $this->assertExtensions();

        parent::__construct($parameters);

        $this->reader = $this->createReader();
    }

    /**
     * Disconnects from the server and destroys the underlying resource and the
     * protocol reader resource when PHP's garbage collector kicks in.
     */
    public function __destruct()
    {
        parent::__destruct();

        phpiredis_reader_destroy($this->reader);
    }

    /**
     * Checks if the socket and phpiredis extensions are loaded in PHP.
     */
    protected function assertExtensions()
    {
        if (!extension_loaded('sockets')) {
            throw new NotSupportedException(
                'The "sockets" extension is required by this connection backend.'
            );
        }

        if (!extension_loaded('phpiredis')) {
            throw new NotSupportedException(
                'The "phpiredis" extension is required by this connection backend.'
            );
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function assertParameters(ParametersInterface $parameters)
    {
        switch ($parameters->scheme) {
            case 'tcp':
            case 'redis':
            case 'unix':
                break;

            default:
                throw new InvalidArgumentException("Invalid scheme: '$parameters->scheme'.");
        }

        if (isset($parameters->persistent)) {
            throw new NotSupportedException(
                'Persistent connections are not supported by this connection backend.'
            );
        }

        return $parameters;
    }

    /**
     * Creates a new instance of the protocol reader resource.
     *
     * @return resource
     */
    private function createReader()
    {
        $reader = phpiredis_reader_create();

        phpiredis_reader_set_status_handler($reader, $this->getStatusHandler());
        phpiredis_reader_set_error_handler($reader, $this->getErrorHandler());

        return $reader;
    }

    /**
     * Returns the underlying protocol reader resource.
     *
     * @return resource
     */
    protected function getReader()
    {
        return $this->reader;
    }

    /**
     * Returns the handler used by the protocol reader for inline responses.
     *
     * @return Closure
     */
    protected function getStatusHandler()
    {
        static $statusHandler;

        if (!$statusHandler) {
            $statusHandler = function ($payload) {
                return StatusResponse::get($payload);
            };
        }

        return $statusHandler;
    }

    /**
     * Returns the handler used by the protocol reader for error responses.
     *
     * @return Closure
     */
    protected function getErrorHandler()
    {
        static $errorHandler;

        if (!$errorHandler) {
            $errorHandler = function ($errorMessage) {
                return new ErrorResponse($errorMessage);
            };
        }

        return $errorHandler;
    }

    /**
     * Helper method used to throw exceptions on socket errors.
     */
    private function emitSocketError()
    {
        $errno = socket_last_error();
        $errstr = socket_strerror($errno);

        $this->disconnect();

        $this->onConnectionError(trim($errstr), $errno);
    }

    /**
     * Gets the address of an host from connection parameters.
     *
     * @param ParametersInterface $parameters Parameters used to initialize the connection.
     *
     * @return string
     */
    protected static function getAddress(ParametersInterface $parameters)
    {
        if (filter_var($host = $parameters->host, FILTER_VALIDATE_IP)) {
            return $host;
        }

        if ($host === $address = gethostbyname($host)) {
            return false;
        }

        return $address;
    }

    /**
     * {@inheritdoc}
     */
    protected function createResource()
    {
        $parameters = $this->parameters;

        if ($parameters->scheme === 'unix') {
            $address = $parameters->path;
            $domain = AF_UNIX;
            $protocol = 0;
        } else {
            if (false === $address = self::getAddress($parameters)) {
                $this->onConnectionError("Cannot resolve the address of '$parameters->host'.");
            }

            $domain = filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? AF_INET6 : AF_INET;
            $protocol = SOL_TCP;
        }

        if (false === $socket = @socket_create($domain, SOCK_STREAM, $protocol)) {
            $this->emitSocketError();
        }

        $this->setSocketOptions($socket, $parameters);
        $this->connectWithTimeout($socket, $address, $parameters);

        return $socket;
    }

    /**
     * Sets options on the socket resource from the connection parameters.
     *
     * @param resource            $socket     Socket resource.
     * @param ParametersInterface $parameters Parameters used to initialize the connection.
     */
    private function setSocketOptions($socket, ParametersInterface $parameters)
    {
        if ($parameters->scheme !== 'unix') {
            if (!socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1)) {
                $this->emitSocketError();
            }

            if (!socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1)) {
                $this->emitSocketError();
            }
        }

        if (isset($parameters->read_write_timeout)) {
            $rwtimeout = (float) $parameters->read_write_timeout;
            $timeoutSec = floor($rwtimeout);
            $timeoutUsec = ($rwtimeout - $timeoutSec) * 1000000;

            $timeout = [
                'sec' => $timeoutSec,
                'usec' => $timeoutUsec,
            ];

            if (!socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, $timeout)) {
                $this->emitSocketError();
            }

            if (!socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, $timeout)) {
                $this->emitSocketError();
            }
        }
    }

    /**
     * Opens the actual connection to the server with a timeout.
     *
     * @param resource            $socket     Socket resource.
     * @param string              $address    IP address (DNS-resolved from hostname)
     * @param ParametersInterface $parameters Parameters used to initialize the connection.
     *
     * @return void
     */
    private function connectWithTimeout($socket, $address, ParametersInterface $parameters)
    {
        socket_set_nonblock($socket);

        if (@socket_connect($socket, $address, (int) $parameters->port) === false) {
            $error = socket_last_error();

            if ($error != SOCKET_EINPROGRESS && $error != SOCKET_EALREADY) {
                $this->emitSocketError();
            }
        }

        socket_set_block($socket);

        $null = null;
        $selectable = [$socket];

        $timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0);
        $timeoutSecs = floor($timeout);
        $timeoutUSecs = ($timeout - $timeoutSecs) * 1000000;

        $selected = socket_select($selectable, $selectable, $null, $timeoutSecs, $timeoutUSecs);

        if ($selected === 2) {
            $this->onConnectionError('Connection refused.', SOCKET_ECONNREFUSED);
        }

        if ($selected === 0) {
            $this->onConnectionError('Connection timed out.', SOCKET_ETIMEDOUT);
        }

        if ($selected === false) {
            $this->emitSocketError();
        }
    }

    /**
     * {@inheritdoc}
     */
    public function connect()
    {
        if (parent::connect() && $this->initCommands) {
            foreach ($this->initCommands as $command) {
                $response = $this->executeCommand($command);

                if ($response instanceof ErrorResponseInterface) {
                    $this->onConnectionError("`{$command->getId()}` failed: {$response->getMessage()}", 0);
                }
            }
        }
    }

    /**
     * {@inheritdoc}
     */
    public function disconnect()
    {
        if ($this->isConnected()) {
            phpiredis_reader_reset($this->reader);
            socket_close($this->getResource());

            parent::disconnect();
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function write($buffer)
    {
        $socket = $this->getResource();

        while (($length = strlen($buffer)) > 0) {
            $written = socket_write($socket, $buffer, $length);

            if ($length === $written) {
                return;
            }

            if ($written === false) {
                $this->onConnectionError('Error while writing bytes to the server.');
            }

            $buffer = substr($buffer, $written);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function read()
    {
        $socket = $this->getResource();
        $reader = $this->reader;

        while (PHPIREDIS_READER_STATE_INCOMPLETE === $state = phpiredis_reader_get_state($reader)) {
            if (@socket_recv($socket, $buffer, 4096, 0) === false || $buffer === '' || $buffer === null) {
                $this->emitSocketError();
            }

            phpiredis_reader_feed($reader, $buffer);
        }

        if ($state === PHPIREDIS_READER_STATE_COMPLETE) {
            return phpiredis_reader_get_reply($reader);
        } else {
            $this->onProtocolError(phpiredis_reader_get_error($reader));

            return;
        }
    }

    /**
     * {@inheritdoc}
     */
    public function writeRequest(CommandInterface $command)
    {
        $arguments = $command->getArguments();
        array_unshift($arguments, $command->getId());

        $this->write(phpiredis_format_command($arguments));
    }

    /**
     * {@inheritdoc}
     */
    public function __wakeup()
    {
        $this->assertExtensions();
        $this->reader = $this->createReader();
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                      predis/src/Connection/Cluster/ClusterInterface.php                                                  0000644                 00000001034 15233650113 0016311 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection\Cluster;

use Predis\Connection\AggregateConnectionInterface;

/**
 * Defines a cluster of Redis servers formed by aggregating multiple connection
 * instances to single Redis nodes.
 */
interface ClusterInterface extends AggregateConnectionInterface
{
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    predis/src/Connection/Cluster/RedisCluster.php                                                      0000644                 00000046424 15233650113 0015473 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection\Cluster;

use ArrayIterator;
use Countable;
use IteratorAggregate;
use OutOfBoundsException;
use Predis\ClientException;
use Predis\Cluster\RedisStrategy as RedisClusterStrategy;
use Predis\Cluster\SlotMap;
use Predis\Cluster\StrategyInterface;
use Predis\Command\CommandInterface;
use Predis\Command\RawCommand;
use Predis\Connection\ConnectionException;
use Predis\Connection\FactoryInterface;
use Predis\Connection\NodeConnectionInterface;
use Predis\NotSupportedException;
use Predis\Response\Error as ErrorResponse;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\ServerException;
use ReturnTypeWillChange;
use Throwable;
use Traversable;

/**
 * Abstraction for a Redis-backed cluster of nodes (Redis >= 3.0.0).
 *
 * This connection backend offers smart support for redis-cluster by handling
 * automatic slots map (re)generation upon -MOVED or -ASK responses returned by
 * Redis when redirecting a client to a different node.
 *
 * The cluster can be pre-initialized using only a subset of the actual nodes in
 * the cluster, Predis will do the rest by adjusting the slots map and creating
 * the missing underlying connection instances on the fly.
 *
 * It is possible to pre-associate connections to a slots range with the "slots"
 * parameter in the form "$first-$last". This can greatly reduce runtime node
 * guessing and redirections.
 *
 * It is also possible to ask for the full and updated slots map directly to one
 * of the nodes and optionally enable such a behaviour upon -MOVED redirections.
 * Asking for the cluster configuration to Redis is actually done by issuing a
 * CLUSTER SLOTS command to a random node in the pool.
 */
class RedisCluster implements ClusterInterface, IteratorAggregate, Countable
{
    private $useClusterSlots = true;
    private $pool = [];
    private $slots = [];
    private $slotmap;
    private $strategy;
    private $connections;
    private $retryLimit = 5;
    private $retryInterval = 10;

    /**
     * @param FactoryInterface  $connections Optional connection factory.
     * @param StrategyInterface $strategy    Optional cluster strategy.
     */
    public function __construct(
        FactoryInterface $connections,
        StrategyInterface $strategy = null
    ) {
        $this->connections = $connections;
        $this->strategy = $strategy ?: new RedisClusterStrategy();
        $this->slotmap = new SlotMap();
    }

    /**
     * Sets the maximum number of retries for commands upon server failure.
     *
     * -1 = unlimited retry attempts
     *  0 = no retry attempts (fails immediately)
     *  n = fail only after n retry attempts
     *
     * @param int $retry Number of retry attempts.
     */
    public function setRetryLimit($retry)
    {
        $this->retryLimit = (int) $retry;
    }

    /**
     * Sets the initial retry interval (milliseconds).
     *
     * @param int $retryInterval Milliseconds between retries.
     */
    public function setRetryInterval($retryInterval)
    {
        $this->retryInterval = (int) $retryInterval;
    }

    /**
     * Returns the retry interval (milliseconds).
     *
     * @return int Milliseconds between retries.
     */
    public function getRetryInterval()
    {
        return (int) $this->retryInterval;
    }

    /**
     * {@inheritdoc}
     */
    public function isConnected()
    {
        foreach ($this->pool as $connection) {
            if ($connection->isConnected()) {
                return true;
            }
        }

        return false;
    }

    /**
     * {@inheritdoc}
     */
    public function connect()
    {
        if ($connection = $this->getRandomConnection()) {
            $connection->connect();
        }
    }

    /**
     * {@inheritdoc}
     */
    public function disconnect()
    {
        foreach ($this->pool as $connection) {
            $connection->disconnect();
        }
    }

    /**
     * {@inheritdoc}
     */
    public function add(NodeConnectionInterface $connection)
    {
        $this->pool[(string) $connection] = $connection;
        $this->slotmap->reset();
    }

    /**
     * {@inheritdoc}
     */
    public function remove(NodeConnectionInterface $connection)
    {
        if (false !== $id = array_search($connection, $this->pool, true)) {
            $this->slotmap->reset();
            $this->slots = array_diff($this->slots, [$connection]);
            unset($this->pool[$id]);

            return true;
        }

        return false;
    }

    /**
     * Removes a connection instance by using its identifier.
     *
     * @param string $connectionID Connection identifier.
     *
     * @return bool True if the connection was in the pool.
     */
    public function removeById($connectionID)
    {
        if (isset($this->pool[$connectionID])) {
            $this->slotmap->reset();
            $this->slots = array_diff($this->slots, [$connectionID]);
            unset($this->pool[$connectionID]);

            return true;
        }

        return false;
    }

    /**
     * Generates the current slots map by guessing the cluster configuration out
     * of the connection parameters of the connections in the pool.
     *
     * Generation is based on the same algorithm used by Redis to generate the
     * cluster, so it is most effective when all of the connections supplied on
     * initialization have the "slots" parameter properly set accordingly to the
     * current cluster configuration.
     */
    public function buildSlotMap()
    {
        $this->slotmap->reset();

        foreach ($this->pool as $connectionID => $connection) {
            $parameters = $connection->getParameters();

            if (!isset($parameters->slots)) {
                continue;
            }

            foreach (explode(',', $parameters->slots) as $slotRange) {
                $slots = explode('-', $slotRange, 2);

                if (!isset($slots[1])) {
                    $slots[1] = $slots[0];
                }

                $this->slotmap->setSlots($slots[0], $slots[1], $connectionID);
            }
        }
    }

    /**
     * Queries the specified node of the cluster to fetch the updated slots map.
     *
     * When the connection fails, this method tries to execute the same command
     * on a different connection picked at random from the pool of known nodes,
     * up until the retry limit is reached.
     *
     * @param NodeConnectionInterface $connection Connection to a node of the cluster.
     *
     * @return mixed
     */
    private function queryClusterNodeForSlotMap(NodeConnectionInterface $connection)
    {
        $retries = 0;
        $retryAfter = $this->retryInterval;
        $command = RawCommand::create('CLUSTER', 'SLOTS');

        while ($retries <= $this->retryLimit) {
            try {
                $response = $connection->executeCommand($command);
                break;
            } catch (ConnectionException $exception) {
                $connection = $exception->getConnection();
                $connection->disconnect();

                $this->remove($connection);

                if ($retries === $this->retryLimit) {
                    throw $exception;
                }

                if (!$connection = $this->getRandomConnection()) {
                    throw new ClientException('No connections left in the pool for `CLUSTER SLOTS`');
                }

                usleep($retryAfter * 1000);
                $retryAfter = $retryAfter * 2;
                ++$retries;
            }
        }

        return $response;
    }

    /**
     * Generates an updated slots map fetching the cluster configuration using
     * the CLUSTER SLOTS command against the specified node or a random one from
     * the pool.
     *
     * @param NodeConnectionInterface $connection Optional connection instance.
     */
    public function askSlotMap(NodeConnectionInterface $connection = null)
    {
        if (!$connection && !$connection = $this->getRandomConnection()) {
            return;
        }

        $this->slotmap->reset();

        $response = $this->queryClusterNodeForSlotMap($connection);

        foreach ($response as $slots) {
            // We only support master servers for now, so we ignore subsequent
            // elements in the $slots array identifying slaves.
            [$start, $end, $master] = $slots;

            if ($master[0] === '') {
                $this->slotmap->setSlots($start, $end, (string) $connection);
            } else {
                $this->slotmap->setSlots($start, $end, "{$master[0]}:{$master[1]}");
            }
        }
    }

    /**
     * Guesses the correct node associated to a given slot using a precalculated
     * slots map, falling back to the same logic used by Redis to initialize a
     * cluster (best-effort).
     *
     * @param int $slot Slot index.
     *
     * @return string Connection ID.
     */
    protected function guessNode($slot)
    {
        if (!$this->pool) {
            throw new ClientException('No connections available in the pool');
        }

        if ($this->slotmap->isEmpty()) {
            $this->buildSlotMap();
        }

        if ($node = $this->slotmap[$slot]) {
            return $node;
        }

        $count = count($this->pool);
        $index = min((int) ($slot / (int) (16384 / $count)), $count - 1);
        $nodes = array_keys($this->pool);

        return $nodes[$index];
    }

    /**
     * Creates a new connection instance from the given connection ID.
     *
     * @param string $connectionID Identifier for the connection.
     *
     * @return NodeConnectionInterface
     */
    protected function createConnection($connectionID)
    {
        $separator = strrpos($connectionID, ':');

        return $this->connections->create([
            'host' => substr($connectionID, 0, $separator),
            'port' => substr($connectionID, $separator + 1),
        ]);
    }

    /**
     * {@inheritdoc}
     */
    public function getConnectionByCommand(CommandInterface $command)
    {
        $slot = $this->strategy->getSlot($command);

        if (!isset($slot)) {
            throw new NotSupportedException(
                "Cannot use '{$command->getId()}' with redis-cluster."
            );
        }

        if (isset($this->slots[$slot])) {
            return $this->slots[$slot];
        } else {
            return $this->getConnectionBySlot($slot);
        }
    }

    /**
     * Returns the connection currently associated to a given slot.
     *
     * @param int $slot Slot index.
     *
     * @return NodeConnectionInterface
     * @throws OutOfBoundsException
     */
    public function getConnectionBySlot($slot)
    {
        if (!SlotMap::isValid($slot)) {
            throw new OutOfBoundsException("Invalid slot [$slot].");
        }

        if (isset($this->slots[$slot])) {
            return $this->slots[$slot];
        }

        $connectionID = $this->guessNode($slot);

        if (!$connection = $this->getConnectionById($connectionID)) {
            $connection = $this->createConnection($connectionID);
            $this->pool[$connectionID] = $connection;
        }

        return $this->slots[$slot] = $connection;
    }

    /**
     * {@inheritdoc}
     */
    public function getConnectionById($connectionID)
    {
        return $this->pool[$connectionID] ?? null;
    }

    /**
     * Returns a random connection from the pool.
     *
     * @return NodeConnectionInterface|null
     */
    protected function getRandomConnection()
    {
        if (!$this->pool) {
            return null;
        }

        return $this->pool[array_rand($this->pool)];
    }

    /**
     * Permanently associates the connection instance to a new slot.
     * The connection is added to the connections pool if not yet included.
     *
     * @param NodeConnectionInterface $connection Connection instance.
     * @param int                     $slot       Target slot index.
     */
    protected function move(NodeConnectionInterface $connection, $slot)
    {
        $this->pool[(string) $connection] = $connection;
        $this->slots[(int) $slot] = $connection;
        $this->slotmap[(int) $slot] = $connection;
    }

    /**
     * Handles -ERR responses returned by Redis.
     *
     * @param CommandInterface       $command Command that generated the -ERR response.
     * @param ErrorResponseInterface $error   Redis error response object.
     *
     * @return mixed
     */
    protected function onErrorResponse(CommandInterface $command, ErrorResponseInterface $error)
    {
        $details = explode(' ', $error->getMessage(), 2);

        switch ($details[0]) {
            case 'MOVED':
                return $this->onMovedResponse($command, $details[1]);

            case 'ASK':
                return $this->onAskResponse($command, $details[1]);

            default:
                return $error;
        }
    }

    /**
     * Handles -MOVED responses by executing again the command against the node
     * indicated by the Redis response.
     *
     * @param CommandInterface $command Command that generated the -MOVED response.
     * @param string           $details Parameters of the -MOVED response.
     *
     * @return mixed
     */
    protected function onMovedResponse(CommandInterface $command, $details)
    {
        [$slot, $connectionID] = explode(' ', $details, 2);

        if (!$connection = $this->getConnectionById($connectionID)) {
            $connection = $this->createConnection($connectionID);
        }

        if ($this->useClusterSlots) {
            $this->askSlotMap($connection);
        }

        $this->move($connection, $slot);

        return $this->executeCommand($command);
    }

    /**
     * Handles -ASK responses by executing again the command against the node
     * indicated by the Redis response.
     *
     * @param CommandInterface $command Command that generated the -ASK response.
     * @param string           $details Parameters of the -ASK response.
     *
     * @return mixed
     */
    protected function onAskResponse(CommandInterface $command, $details)
    {
        [$slot, $connectionID] = explode(' ', $details, 2);

        if (!$connection = $this->getConnectionById($connectionID)) {
            $connection = $this->createConnection($connectionID);
        }

        $connection->executeCommand(RawCommand::create('ASKING'));

        return $connection->executeCommand($command);
    }

    /**
     * Ensures that a command is executed one more time on connection failure.
     *
     * The connection to the node that generated the error is evicted from the
     * pool before trying to fetch an updated slots map from another node. If
     * the new slots map points to an unreachable server the client gives up and
     * throws the exception as the nodes participating in the cluster may still
     * have to agree that something changed in the configuration of the cluster.
     *
     * @param CommandInterface $command Command instance.
     * @param string           $method  Actual method.
     *
     * @return mixed
     */
    private function retryCommandOnFailure(CommandInterface $command, $method)
    {
        $retries = 0;
        $retryAfter = $this->retryInterval;

        while ($retries <= $this->retryLimit) {
            try {
                $response = $this->getConnectionByCommand($command)->$method($command);

                if ($response instanceof ErrorResponse) {
                    $message = $response->getMessage();

                    if (strpos($message, 'CLUSTERDOWN') !== false) {
                        throw new ServerException($message);
                    }
                }

                break;
            } catch (Throwable $exception) {
                usleep($retryAfter * 1000);
                $retryAfter = $retryAfter * 2;

                if ($exception instanceof ConnectionException) {
                    $connection = $exception->getConnection();

                    if ($connection) {
                        $connection->disconnect();
                        $this->remove($connection);
                    }
                }

                if ($retries === $this->retryLimit) {
                    throw $exception;
                }

                if ($this->useClusterSlots) {
                    $this->askSlotMap();
                }

                ++$retries;
            }
        }

        return $response;
    }

    /**
     * {@inheritdoc}
     */
    public function writeRequest(CommandInterface $command)
    {
        $this->retryCommandOnFailure($command, __FUNCTION__);
    }

    /**
     * {@inheritdoc}
     */
    public function readResponse(CommandInterface $command)
    {
        return $this->retryCommandOnFailure($command, __FUNCTION__);
    }

    /**
     * {@inheritdoc}
     */
    public function executeCommand(CommandInterface $command)
    {
        $response = $this->retryCommandOnFailure($command, __FUNCTION__);

        if ($response instanceof ErrorResponseInterface) {
            return $this->onErrorResponse($command, $response);
        }

        return $response;
    }

    /**
     * @return int
     */
    #[ReturnTypeWillChange]
    public function count()
    {
        return count($this->pool);
    }

    /**
     * @return Traversable<string, NodeConnectionInterface>
     */
    #[ReturnTypeWillChange]
    public function getIterator()
    {
        if ($this->slotmap->isEmpty()) {
            $this->useClusterSlots ? $this->askSlotMap() : $this->buildSlotMap();
        }

        $connections = [];

        foreach ($this->slotmap->getNodes() as $node) {
            if (!$connection = $this->getConnectionById($node)) {
                $this->add($connection = $this->createConnection($node));
            }

            $connections[] = $connection;
        }

        return new ArrayIterator($connections);
    }

    /**
     * Returns the underlying slot map.
     *
     * @return SlotMap
     */
    public function getSlotMap()
    {
        return $this->slotmap;
    }

    /**
     * Returns the underlying command hash strategy used to hash commands by
     * using keys found in their arguments.
     *
     * @return StrategyInterface
     */
    public function getClusterStrategy()
    {
        return $this->strategy;
    }

    /**
     * Returns the underlying connection factory used to create new connection
     * instances to Redis nodes indicated by redis-cluster.
     *
     * @return FactoryInterface
     */
    public function getConnectionFactory()
    {
        return $this->connections;
    }

    /**
     * Enables automatic fetching of the current slots map from one of the nodes
     * using the CLUSTER SLOTS command. This option is enabled by default as
     * asking the current slots map to Redis upon -MOVED responses may reduce
     * overhead by eliminating the trial-and-error nature of the node guessing
     * procedure, mostly when targeting many keys that would end up in a lot of
     * redirections.
     *
     * The slots map can still be manually fetched using the askSlotMap()
     * method whether or not this option is enabled.
     *
     * @param bool $value Enable or disable the use of CLUSTER SLOTS.
     */
    public function useClusterSlots($value)
    {
        $this->useClusterSlots = (bool) $value;
    }
}
                                                                                                                                                                                                                                            predis/src/Connection/Cluster/PredisCluster.php                                                     0000644                 00000012663 15233650113 0015651 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection\Cluster;

use ArrayIterator;
use Countable;
use IteratorAggregate;
use Predis\Cluster\PredisStrategy;
use Predis\Cluster\StrategyInterface;
use Predis\Command\CommandInterface;
use Predis\Connection\NodeConnectionInterface;
use Predis\NotSupportedException;
use ReturnTypeWillChange;
use Traversable;

/**
 * Abstraction for a cluster of aggregate connections to various Redis servers
 * implementing client-side sharding based on pluggable distribution strategies.
 */
class PredisCluster implements ClusterInterface, IteratorAggregate, Countable
{
    /**
     * @var NodeConnectionInterface[]
     */
    private $pool = [];

    /**
     * @var NodeConnectionInterface[]
     */
    private $aliases = [];

    /**
     * @var StrategyInterface
     */
    private $strategy;

    /**
     * @var \Predis\Cluster\Distributor\DistributorInterface
     */
    private $distributor;

    /**
     * @param StrategyInterface $strategy Optional cluster strategy.
     */
    public function __construct(StrategyInterface $strategy = null)
    {
        $this->strategy = $strategy ?: new PredisStrategy();
        $this->distributor = $this->strategy->getDistributor();
    }

    /**
     * {@inheritdoc}
     */
    public function isConnected()
    {
        foreach ($this->pool as $connection) {
            if ($connection->isConnected()) {
                return true;
            }
        }

        return false;
    }

    /**
     * {@inheritdoc}
     */
    public function connect()
    {
        foreach ($this->pool as $connection) {
            $connection->connect();
        }
    }

    /**
     * {@inheritdoc}
     */
    public function disconnect()
    {
        foreach ($this->pool as $connection) {
            $connection->disconnect();
        }
    }

    /**
     * {@inheritdoc}
     */
    public function add(NodeConnectionInterface $connection)
    {
        $parameters = $connection->getParameters();

        $this->pool[(string) $connection] = $connection;

        if (isset($parameters->alias)) {
            $this->aliases[$parameters->alias] = $connection;
        }

        $this->distributor->add($connection, $parameters->weight);
    }

    /**
     * {@inheritdoc}
     */
    public function remove(NodeConnectionInterface $connection)
    {
        if (false !== $id = array_search($connection, $this->pool, true)) {
            unset($this->pool[$id]);
            $this->distributor->remove($connection);

            if ($this->aliases && $alias = $connection->getParameters()->alias) {
                unset($this->aliases[$alias]);
            }

            return true;
        }

        return false;
    }

    /**
     * {@inheritdoc}
     */
    public function getConnectionByCommand(CommandInterface $command)
    {
        $slot = $this->strategy->getSlot($command);

        if (!isset($slot)) {
            throw new NotSupportedException(
                "Cannot use '{$command->getId()}' over clusters of connections."
            );
        }

        return $this->distributor->getBySlot($slot);
    }

    /**
     * {@inheritdoc}
     */
    public function getConnectionById($id)
    {
        return $this->pool[$id] ?? null;
    }

    /**
     * Returns a connection instance by its alias.
     *
     * @param string $alias Connection alias.
     *
     * @return NodeConnectionInterface|null
     */
    public function getConnectionByAlias($alias)
    {
        return $this->aliases[$alias] ?? null;
    }

    /**
     * Retrieves a connection instance by slot.
     *
     * @param string $slot Slot name.
     *
     * @return NodeConnectionInterface|null
     */
    public function getConnectionBySlot($slot)
    {
        return $this->distributor->getBySlot($slot);
    }

    /**
     * Retrieves a connection instance from the cluster using a key.
     *
     * @param string $key Key string.
     *
     * @return NodeConnectionInterface
     */
    public function getConnectionByKey($key)
    {
        $hash = $this->strategy->getSlotByKey($key);

        return $this->distributor->getBySlot($hash);
    }

    /**
     * Returns the underlying command hash strategy used to hash commands by
     * using keys found in their arguments.
     *
     * @return StrategyInterface
     */
    public function getClusterStrategy()
    {
        return $this->strategy;
    }

    /**
     * @return int
     */
    #[ReturnTypeWillChange]
    public function count()
    {
        return count($this->pool);
    }

    /**
     * @return Traversable<string, NodeConnectionInterface>
     */
    #[ReturnTypeWillChange]
    public function getIterator()
    {
        return new ArrayIterator($this->pool);
    }

    /**
     * {@inheritdoc}
     */
    public function writeRequest(CommandInterface $command)
    {
        $this->getConnectionByCommand($command)->writeRequest($command);
    }

    /**
     * {@inheritdoc}
     */
    public function readResponse(CommandInterface $command)
    {
        return $this->getConnectionByCommand($command)->readResponse($command);
    }

    /**
     * {@inheritdoc}
     */
    public function executeCommand(CommandInterface $command)
    {
        return $this->getConnectionByCommand($command)->executeCommand($command);
    }
}
                                                                             predis/src/Connection/StreamConnection.php                                                          0000644                 00000026545 15233650113 0014717 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection;

use InvalidArgumentException;
use Predis\Command\CommandInterface;
use Predis\Response\Error as ErrorResponse;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\Status as StatusResponse;

/**
 * Standard connection to Redis servers implemented on top of PHP's streams.
 * The connection parameters supported by this class are:.
 *
 *  - scheme: it can be either 'redis', 'tcp', 'rediss', 'tls' or 'unix'.
 *  - host: hostname or IP address of the server.
 *  - port: TCP port of the server.
 *  - path: path of a UNIX domain socket when scheme is 'unix'.
 *  - timeout: timeout to perform the connection (default is 5 seconds).
 *  - read_write_timeout: timeout of read / write operations.
 *  - async_connect: performs the connection asynchronously.
 *  - tcp_nodelay: enables or disables Nagle's algorithm for coalescing.
 *  - persistent: the connection is left intact after a GC collection.
 *  - ssl: context options array (see http://php.net/manual/en/context.ssl.php)
 */
class StreamConnection extends AbstractConnection
{
    /**
     * Disconnects from the server and destroys the underlying resource when the
     * garbage collector kicks in only if the connection has not been marked as
     * persistent.
     */
    public function __destruct()
    {
        if (isset($this->parameters->persistent) && $this->parameters->persistent) {
            return;
        }

        $this->disconnect();
    }

    /**
     * {@inheritdoc}
     */
    protected function assertParameters(ParametersInterface $parameters)
    {
        switch ($parameters->scheme) {
            case 'tcp':
            case 'redis':
            case 'unix':
            case 'tls':
            case 'rediss':
                break;

            default:
                throw new InvalidArgumentException("Invalid scheme: '$parameters->scheme'.");
        }

        return $parameters;
    }

    /**
     * {@inheritdoc}
     */
    protected function createResource()
    {
        switch ($this->parameters->scheme) {
            case 'tcp':
            case 'redis':
                return $this->tcpStreamInitializer($this->parameters);

            case 'unix':
                return $this->unixStreamInitializer($this->parameters);

            case 'tls':
            case 'rediss':
                return $this->tlsStreamInitializer($this->parameters);

            default:
                throw new InvalidArgumentException("Invalid scheme: '{$this->parameters->scheme}'.");
        }
    }

    /**
     * Creates a connected stream socket resource.
     *
     * @param ParametersInterface $parameters Connection parameters.
     * @param string              $address    Address for stream_socket_client().
     * @param int                 $flags      Flags for stream_socket_client().
     *
     * @return resource
     */
    protected function createStreamSocket(ParametersInterface $parameters, $address, $flags)
    {
        $timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0);
        $context = stream_context_create(['socket' => ['tcp_nodelay' => (bool) $parameters->tcp_nodelay]]);

        if (!$resource = @stream_socket_client($address, $errno, $errstr, $timeout, $flags, $context)) {
            $this->onConnectionError(trim($errstr), $errno);
        }

        if (isset($parameters->read_write_timeout)) {
            $rwtimeout = (float) $parameters->read_write_timeout;
            $rwtimeout = $rwtimeout > 0 ? $rwtimeout : -1;
            $timeoutSeconds = floor($rwtimeout);
            $timeoutUSeconds = ($rwtimeout - $timeoutSeconds) * 1000000;
            stream_set_timeout($resource, $timeoutSeconds, $timeoutUSeconds);
        }

        return $resource;
    }

    /**
     * Initializes a TCP stream resource.
     *
     * @param ParametersInterface $parameters Initialization parameters for the connection.
     *
     * @return resource
     */
    protected function tcpStreamInitializer(ParametersInterface $parameters)
    {
        if (!filter_var($parameters->host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
            $address = "tcp://$parameters->host:$parameters->port";
        } else {
            $address = "tcp://[$parameters->host]:$parameters->port";
        }

        $flags = STREAM_CLIENT_CONNECT;

        if (isset($parameters->async_connect) && $parameters->async_connect) {
            $flags |= STREAM_CLIENT_ASYNC_CONNECT;
        }

        if (isset($parameters->persistent)) {
            if (false !== $persistent = filter_var($parameters->persistent, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)) {
                $flags |= STREAM_CLIENT_PERSISTENT;

                if ($persistent === null) {
                    $address = "{$address}/{$parameters->persistent}";
                }
            }
        }

        return $this->createStreamSocket($parameters, $address, $flags);
    }

    /**
     * Initializes a UNIX stream resource.
     *
     * @param ParametersInterface $parameters Initialization parameters for the connection.
     *
     * @return resource
     */
    protected function unixStreamInitializer(ParametersInterface $parameters)
    {
        if (!isset($parameters->path)) {
            throw new InvalidArgumentException('Missing UNIX domain socket path.');
        }

        $flags = STREAM_CLIENT_CONNECT;

        if (isset($parameters->persistent)) {
            if (false !== $persistent = filter_var($parameters->persistent, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)) {
                $flags |= STREAM_CLIENT_PERSISTENT;

                if ($persistent === null) {
                    throw new InvalidArgumentException(
                        'Persistent connection IDs are not supported when using UNIX domain sockets.'
                    );
                }
            }
        }

        return $this->createStreamSocket($parameters, "unix://{$parameters->path}", $flags);
    }

    /**
     * Initializes a SSL-encrypted TCP stream resource.
     *
     * @param ParametersInterface $parameters Initialization parameters for the connection.
     *
     * @return resource
     */
    protected function tlsStreamInitializer(ParametersInterface $parameters)
    {
        $resource = $this->tcpStreamInitializer($parameters);
        $metadata = stream_get_meta_data($resource);

        // Detect if crypto mode is already enabled for this stream (PHP >= 7.0.0).
        if (isset($metadata['crypto'])) {
            return $resource;
        }

        if (isset($parameters->ssl) && is_array($parameters->ssl)) {
            $options = $parameters->ssl;
        } else {
            $options = [];
        }

        if (!isset($options['crypto_type'])) {
            $options['crypto_type'] = STREAM_CRYPTO_METHOD_TLS_CLIENT;
        }

        if (!stream_context_set_option($resource, ['ssl' => $options])) {
            $this->onConnectionError('Error while setting SSL context options');
        }

        if (!stream_socket_enable_crypto($resource, true, $options['crypto_type'])) {
            $this->onConnectionError('Error while switching to encrypted communication');
        }

        return $resource;
    }

    /**
     * {@inheritdoc}
     */
    public function connect()
    {
        if (parent::connect() && $this->initCommands) {
            foreach ($this->initCommands as $command) {
                $response = $this->executeCommand($command);

                if ($response instanceof ErrorResponseInterface && $command->getId() === 'CLIENT') {
                    // Do nothing on CLIENT SETINFO command failure
                } elseif ($response instanceof ErrorResponseInterface) {
                    $this->onConnectionError("`{$command->getId()}` failed: {$response->getMessage()}", 0);
                }
            }
        }
    }

    /**
     * {@inheritdoc}
     */
    public function disconnect()
    {
        if ($this->isConnected()) {
            $resource = $this->getResource();
            if (is_resource($resource)) {
                fclose($resource);
            }
            parent::disconnect();
        }
    }

    /**
     * Performs a write operation over the stream of the buffer containing a
     * command serialized with the Redis wire protocol.
     *
     * @param string $buffer Representation of a command in the Redis wire protocol.
     */
    protected function write($buffer)
    {
        $socket = $this->getResource();

        while (($length = strlen($buffer)) > 0) {
            $written = is_resource($socket) ? @fwrite($socket, $buffer) : false;

            if ($length === $written) {
                return;
            }

            if ($written === false || $written === 0) {
                $this->onConnectionError('Error while writing bytes to the server.');
            }

            $buffer = substr($buffer, $written);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function read()
    {
        $socket = $this->getResource();
        $chunk = fgets($socket);

        if ($chunk === false || $chunk === '') {
            $this->onConnectionError('Error while reading line from the server.');
        }

        $prefix = $chunk[0];
        $payload = substr($chunk, 1, -2);

        switch ($prefix) {
            case '+':
                return StatusResponse::get($payload);

            case '$':
                $size = (int) $payload;

                if ($size === -1) {
                    return;
                }

                $bulkData = '';
                $bytesLeft = ($size += 2);

                do {
                    $chunk = is_resource($socket) ? fread($socket, min($bytesLeft, 4096)) : false;

                    if ($chunk === false || $chunk === '') {
                        $this->onConnectionError('Error while reading bytes from the server.');
                    }

                    $bulkData .= $chunk;
                    $bytesLeft = $size - strlen($bulkData);
                } while ($bytesLeft > 0);

                return substr($bulkData, 0, -2);

            case '*':
                $count = (int) $payload;

                if ($count === -1) {
                    return;
                }

                $multibulk = [];

                for ($i = 0; $i < $count; ++$i) {
                    $multibulk[$i] = $this->read();
                }

                return $multibulk;

            case ':':
                $integer = (int) $payload;

                return $integer == $payload ? $integer : $payload;

            case '-':
                return new ErrorResponse($payload);

            default:
                $this->onProtocolError("Unknown response prefix: '$prefix'.");

                return;
        }
    }

    /**
     * {@inheritdoc}
     */
    public function writeRequest(CommandInterface $command)
    {
        $commandID = $command->getId();
        $arguments = $command->getArguments();

        $cmdlen = strlen($commandID);
        $reqlen = count($arguments) + 1;

        $buffer = "*{$reqlen}\r\n\${$cmdlen}\r\n{$commandID}\r\n";

        foreach ($arguments as $argument) {
            $arglen = strlen(strval($argument));
            $buffer .= "\${$arglen}\r\n{$argument}\r\n";
        }

        $this->write($buffer);
    }
}
                                                                                                                                                           predis/src/Connection/Factory.php                                                                   0000644                 00000013032 15233650113 0013036 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection;

use InvalidArgumentException;
use Predis\Client;
use Predis\Command\RawCommand;
use ReflectionClass;
use UnexpectedValueException;

/**
 * Standard connection factory for creating connections to Redis nodes.
 */
class Factory implements FactoryInterface
{
    private $defaults = [];

    protected $schemes = [
        'tcp' => 'Predis\Connection\StreamConnection',
        'unix' => 'Predis\Connection\StreamConnection',
        'tls' => 'Predis\Connection\StreamConnection',
        'redis' => 'Predis\Connection\StreamConnection',
        'rediss' => 'Predis\Connection\StreamConnection',
        'http' => 'Predis\Connection\WebdisConnection',
    ];

    /**
     * Checks if the provided argument represents a valid connection class
     * implementing Predis\Connection\NodeConnectionInterface. Optionally,
     * callable objects are used for lazy initialization of connection objects.
     *
     * @param mixed $initializer FQN of a connection class or a callable for lazy initialization.
     *
     * @return mixed
     * @throws InvalidArgumentException
     */
    protected function checkInitializer($initializer)
    {
        if (is_callable($initializer)) {
            return $initializer;
        }

        $class = new ReflectionClass($initializer);

        if (!$class->isSubclassOf('Predis\Connection\NodeConnectionInterface')) {
            throw new InvalidArgumentException(
                'A connection initializer must be a valid connection class or a callable object.'
            );
        }

        return $initializer;
    }

    /**
     * {@inheritdoc}
     */
    public function define($scheme, $initializer)
    {
        $this->schemes[$scheme] = $this->checkInitializer($initializer);
    }

    /**
     * {@inheritdoc}
     */
    public function undefine($scheme)
    {
        unset($this->schemes[$scheme]);
    }

    /**
     * {@inheritdoc}
     */
    public function create($parameters)
    {
        if (!$parameters instanceof ParametersInterface) {
            $parameters = $this->createParameters($parameters);
        }

        $scheme = $parameters->scheme;

        if (!isset($this->schemes[$scheme])) {
            throw new InvalidArgumentException("Unknown connection scheme: '$scheme'.");
        }

        $initializer = $this->schemes[$scheme];

        if (is_callable($initializer)) {
            $connection = call_user_func($initializer, $parameters, $this);
        } else {
            $connection = new $initializer($parameters);
            $this->prepareConnection($connection);
        }

        if (!$connection instanceof NodeConnectionInterface) {
            throw new UnexpectedValueException(
                'Objects returned by connection initializers must implement ' .
                "'Predis\Connection\NodeConnectionInterface'."
            );
        }

        return $connection;
    }

    /**
     * Assigns a default set of parameters applied to new connections.
     *
     * The set of parameters passed to create a new connection have precedence
     * over the default values set for the connection factory.
     *
     * @param array $parameters Set of connection parameters.
     */
    public function setDefaultParameters(array $parameters)
    {
        $this->defaults = $parameters;
    }

    /**
     * Returns the default set of parameters applied to new connections.
     *
     * @return array
     */
    public function getDefaultParameters()
    {
        return $this->defaults;
    }

    /**
     * Creates a connection parameters instance from the supplied argument.
     *
     * @param mixed $parameters Original connection parameters.
     *
     * @return ParametersInterface
     */
    protected function createParameters($parameters)
    {
        if (is_string($parameters)) {
            $parameters = Parameters::parse($parameters);
        } else {
            $parameters = $parameters ?: [];
        }

        if ($this->defaults) {
            $parameters += $this->defaults;
        }

        return new Parameters($parameters);
    }

    /**
     * Prepares a connection instance after its initialization.
     *
     * @param NodeConnectionInterface $connection Connection instance.
     */
    protected function prepareConnection(NodeConnectionInterface $connection)
    {
        $parameters = $connection->getParameters();

        if (isset($parameters->password) && strlen($parameters->password)) {
            $cmdAuthArgs = isset($parameters->username) && strlen($parameters->username)
                ? [$parameters->username, $parameters->password]
                : [$parameters->password];

            $connection->addConnectCommand(
                new RawCommand('AUTH', $cmdAuthArgs)
            );
        }

        if ($parameters->client_info ?? false && !$connection instanceof RelayConnection) {
            $connection->addConnectCommand(
                new RawCommand('CLIENT', ['SETINFO', 'LIB-NAME', 'predis'])
            );

            $connection->addConnectCommand(
                new RawCommand('CLIENT', ['SETINFO', 'LIB-VER', Client::VERSION])
            );
        }

        if (isset($parameters->database) && strlen($parameters->database)) {
            $connection->addConnectCommand(
                new RawCommand('SELECT', [$parameters->database])
            );
        }
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      predis/src/Connection/CompositeConnectionInterface.php                                              0000644                 00000002233 15233650113 0017233 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection;

/**
 * Defines a connection to communicate with a single Redis server that leverages
 * an external protocol processor to handle pluggable protocol handlers.
 */
interface CompositeConnectionInterface extends NodeConnectionInterface
{
    /**
     * Returns the protocol processor used by the connection.
     */
    public function getProtocol();

    /**
     * Writes the buffer containing over the connection.
     *
     * @param string $buffer String buffer to be sent over the connection.
     */
    public function writeBuffer($buffer);

    /**
     * Reads the given number of bytes from the connection.
     *
     * @param int $length Number of bytes to read from the connection.
     *
     * @return string
     */
    public function readBuffer($length);

    /**
     * Reads a line from the connection.
     *
     * @return string
     */
    public function readLine();
}
                                                                                                                                                                                                                                                                                                                                                                     predis/src/Connection/ConnectionInterface.php                                                       0000644                 00000002754 15233650113 0015360 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Connection;

use Predis\Command\CommandInterface;

/**
 * Defines a connection object used to communicate with one or multiple
 * Redis servers.
 */
interface ConnectionInterface
{
    /**
     * Opens the connection to Redis.
     */
    public function connect();

    /**
     * Closes the connection to Redis.
     */
    public function disconnect();

    /**
     * Checks if the connection to Redis is considered open.
     *
     * @return bool
     */
    public function isConnected();

    /**
     * Writes the request for the given command over the connection.
     *
     * @param CommandInterface $command Command instance.
     */
    public function writeRequest(CommandInterface $command);

    /**
     * Reads the response to the given command from the connection.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return mixed
     */
    public function readResponse(CommandInterface $command);

    /**
     * Writes a request for the given command over the connection and reads back
     * the response returned by Redis.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return mixed
     */
    public function executeCommand(CommandInterface $command);
}
                    predis/src/Session/Handler.php                                                                      0000644                 00000006074 15233650113 0012340 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Session;

use Predis\ClientInterface;
use ReturnTypeWillChange;
use SessionHandlerInterface;

/**
 * Session handler class that relies on Predis\Client to store PHP's sessions
 * data into one or multiple Redis servers.
 *
 * This class is mostly intended for PHP 5.4 but it can be used under PHP 5.3
 * provided that a polyfill for `SessionHandlerInterface` is defined by either
 * you or an external package such as `symfony/http-foundation`.
 */
class Handler implements SessionHandlerInterface
{
    protected $client;
    protected $ttl;

    /**
     * @param ClientInterface $client  Fully initialized client instance.
     * @param array           $options Session handler options.
     */
    public function __construct(ClientInterface $client, array $options = [])
    {
        $this->client = $client;

        if (isset($options['gc_maxlifetime'])) {
            $this->ttl = (int) $options['gc_maxlifetime'];
        } else {
            $this->ttl = ini_get('session.gc_maxlifetime');
        }
    }

    /**
     * Registers this instance as the current session handler.
     */
    public function register()
    {
        session_set_save_handler($this, true);
    }

    /**
     * @param  string $save_path
     * @param  string $session_id
     * @return bool
     */
    #[ReturnTypeWillChange]
    public function open($save_path, $session_id)
    {
        // NOOP
        return true;
    }

    /**
     * @return bool
     */
    #[ReturnTypeWillChange]
    public function close()
    {
        // NOOP
        return true;
    }

    /**
     * @param  int  $maxlifetime
     * @return bool
     */
    #[ReturnTypeWillChange]
    public function gc($maxlifetime)
    {
        // NOOP
        return true;
    }

    /**
     * @param  string $session_id
     * @return string
     */
    #[ReturnTypeWillChange]
    public function read($session_id)
    {
        if ($data = $this->client->get($session_id)) {
            return $data;
        }

        return '';
    }

    /**
     * @param  string $session_id
     * @param  string $session_data
     * @return bool
     */
    #[ReturnTypeWillChange]
    public function write($session_id, $session_data)
    {
        $this->client->setex($session_id, $this->ttl, $session_data);

        return true;
    }

    /**
     * @param  string $session_id
     * @return bool
     */
    #[ReturnTypeWillChange]
    public function destroy($session_id)
    {
        $this->client->del($session_id);

        return true;
    }

    /**
     * Returns the underlying client instance.
     *
     * @return ClientInterface
     */
    public function getClient()
    {
        return $this->client;
    }

    /**
     * Returns the session max lifetime value.
     *
     * @return int
     */
    public function getMaxLifeTime()
    {
        return $this->ttl;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                    predis/src/Autoloader.php                                                                           0000644                 00000003330 15233650113 0011427 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis;

/**
 * Implements a lightweight PSR-0 compliant autoloader for Predis.
 *
 * @author Eric Naeseth <eric@thumbtack.com>
 * @author Daniele Alessandri <suppakilla@gmail.com>
 * @codeCoverageIgnore
 */
class Autoloader
{
    private $directory;
    private $prefix;
    private $prefixLength;

    /**
     * @param string $baseDirectory Base directory where the source files are located.
     */
    public function __construct($baseDirectory = __DIR__)
    {
        $this->directory = $baseDirectory;
        $this->prefix = __NAMESPACE__ . '\\';
        $this->prefixLength = strlen($this->prefix);
    }

    /**
     * Registers the autoloader class with the PHP SPL autoloader.
     *
     * @param bool $prepend Prepend the autoloader on the stack instead of appending it.
     */
    public static function register($prepend = false)
    {
        spl_autoload_register([new self(), 'autoload'], true, $prepend);
    }

    /**
     * Loads a class from a file using its fully qualified name.
     *
     * @param string $className Fully qualified name of a class.
     */
    public function autoload($className)
    {
        if (0 === strpos($className, $this->prefix)) {
            $parts = explode('\\', substr($className, $this->prefixLength));
            $filepath = $this->directory . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $parts) . '.php';

            if (is_file($filepath)) {
                require $filepath;
            }
        }
    }
}
                                                                                                                                                                                                                                                                                                        predis/src/Cluster/StrategyInterface.php                                                            0000644                 00000002440 15233650113 0014375 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 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 Predis\Cluster\Distributor\DistributorInterface;
use Predis\Command\CommandInterface;

/**
 * Interface for classes defining the strategy used to calculate an hash out of
 * keys extracted from supported commands.
 *
 * This is mostly useful to support clustering via client-side sharding.
 */
interface StrategyInterface
{
    /**
     * Returns a slot for the given command used for clustering distribution or
     * NULL when this is not possible.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return int|null
     */
    public function getSlot(CommandInterface $command);

    /**
     * Returns a slot for the given key used for clustering distribution or NULL
     * when this is not possible.
     *
     * @param string $key Key string.
     *
     * @return int|null
     */
    public function getSlotByKey($key);

    /**
     * Returns a distributor instance to be used by the cluster.
     *
     * @return DistributorInterface
     */
    public function getDistributor();
}
                                                                                                                                                                                                                                predis/src/Cluster/Hash/PhpiredisCRC16.php                                                          0000644                 00000001701 15233650113 0014262 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 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);
    }
}
                                                               predis/src/Cluster/Hash/CRC16.php                                                                   0000644                 00000006147 15233650113 0012423 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 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;

/**
 * Hash generator implementing the CRC-CCITT-16 algorithm used by redis-cluster.
 */
class CRC16 implements HashGeneratorInterface
{
    private static $CCITT_16 = [
        0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
        0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
        0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
        0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
        0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
        0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
        0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
        0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
        0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
        0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
        0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
        0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
        0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
        0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
        0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
        0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
        0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
        0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
        0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
        0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
        0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
        0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
        0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
        0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
        0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
        0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
        0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
        0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
        0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
        0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
        0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
        0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0,
    ];

    /**
     * {@inheritdoc}
     */
    public function hash($value)
    {
        // CRC-CCITT-16 algorithm
        $crc = 0;
        $CCITT_16 = self::$CCITT_16;

        $value = (string) $value;
        $strlen = strlen($value);

        for ($i = 0; $i < $strlen; ++$i) {
            $crc = (($crc << 8) ^ $CCITT_16[($crc >> 8) ^ ord($value[$i])]) & 0xFFFF;
        }

        return $crc;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                         predis/src/Cluster/Hash/HashGeneratorInterface.php                                                  0000644                 00000001214 15233650113 0016206 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 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;

/**
 * An hash generator implements the logic used to calculate the hash of a key to
 * distribute operations among Redis nodes.
 */
interface HashGeneratorInterface
{
    /**
     * Generates an hash from a string to be used for distribution.
     *
     * @param string $value String value.
     *
     * @return int
     */
    public function hash($value);
}
                                                                                                                                                                                                                                                                                                                                                                                    predis/src/Cluster/ClusterStrategy.php                                                              0000644                 00000036440 15233650113 0014125 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 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 InvalidArgumentException;
use Predis\Command\CommandInterface;
use Predis\Command\ScriptCommand;

/**
 * Common class implementing the logic needed to support clustering strategies.
 */
abstract class ClusterStrategy implements StrategyInterface
{
    protected $commands;

    public function __construct()
    {
        $this->commands = $this->getDefaultCommands();
    }

    /**
     * Returns the default map of supported commands with their handlers.
     *
     * @return array
     */
    protected function getDefaultCommands()
    {
        $getKeyFromFirstArgument = [$this, 'getKeyFromFirstArgument'];
        $getKeyFromAllArguments = [$this, 'getKeyFromAllArguments'];

        return [
            /* commands operating on the key space */
            'EXISTS' => $getKeyFromAllArguments,
            'DEL' => $getKeyFromAllArguments,
            'TYPE' => $getKeyFromFirstArgument,
            'EXPIRE' => $getKeyFromFirstArgument,
            'EXPIREAT' => $getKeyFromFirstArgument,
            'PERSIST' => $getKeyFromFirstArgument,
            'PEXPIRE' => $getKeyFromFirstArgument,
            'PEXPIREAT' => $getKeyFromFirstArgument,
            'TTL' => $getKeyFromFirstArgument,
            'PTTL' => $getKeyFromFirstArgument,
            'SORT' => [$this, 'getKeyFromSortCommand'],
            'DUMP' => $getKeyFromFirstArgument,
            'RESTORE' => $getKeyFromFirstArgument,
            'FLUSHDB' => [$this, 'getFakeKey'],

            /* commands operating on string values */
            'APPEND' => $getKeyFromFirstArgument,
            'DECR' => $getKeyFromFirstArgument,
            'DECRBY' => $getKeyFromFirstArgument,
            'GET' => $getKeyFromFirstArgument,
            'GETBIT' => $getKeyFromFirstArgument,
            'MGET' => $getKeyFromAllArguments,
            'SET' => $getKeyFromFirstArgument,
            'GETRANGE' => $getKeyFromFirstArgument,
            'GETSET' => $getKeyFromFirstArgument,
            'INCR' => $getKeyFromFirstArgument,
            'INCRBY' => $getKeyFromFirstArgument,
            'INCRBYFLOAT' => $getKeyFromFirstArgument,
            'SETBIT' => $getKeyFromFirstArgument,
            'SETEX' => $getKeyFromFirstArgument,
            'MSET' => [$this, 'getKeyFromInterleavedArguments'],
            'MSETNX' => [$this, 'getKeyFromInterleavedArguments'],
            'SETNX' => $getKeyFromFirstArgument,
            'SETRANGE' => $getKeyFromFirstArgument,
            'STRLEN' => $getKeyFromFirstArgument,
            'SUBSTR' => $getKeyFromFirstArgument,
            'BITOP' => [$this, 'getKeyFromBitOp'],
            'BITCOUNT' => $getKeyFromFirstArgument,
            'BITFIELD' => $getKeyFromFirstArgument,

            /* commands operating on lists */
            'LINSERT' => $getKeyFromFirstArgument,
            'LINDEX' => $getKeyFromFirstArgument,
            'LLEN' => $getKeyFromFirstArgument,
            'LPOP' => $getKeyFromFirstArgument,
            'RPOP' => $getKeyFromFirstArgument,
            'RPOPLPUSH' => $getKeyFromAllArguments,
            'BLPOP' => [$this, 'getKeyFromBlockingListCommands'],
            'BRPOP' => [$this, 'getKeyFromBlockingListCommands'],
            'BRPOPLPUSH' => [$this, 'getKeyFromBlockingListCommands'],
            'LPUSH' => $getKeyFromFirstArgument,
            'LPUSHX' => $getKeyFromFirstArgument,
            'RPUSH' => $getKeyFromFirstArgument,
            'RPUSHX' => $getKeyFromFirstArgument,
            'LRANGE' => $getKeyFromFirstArgument,
            'LREM' => $getKeyFromFirstArgument,
            'LSET' => $getKeyFromFirstArgument,
            'LTRIM' => $getKeyFromFirstArgument,

            /* commands operating on sets */
            'SADD' => $getKeyFromFirstArgument,
            'SCARD' => $getKeyFromFirstArgument,
            'SDIFF' => $getKeyFromAllArguments,
            'SDIFFSTORE' => $getKeyFromAllArguments,
            'SINTER' => $getKeyFromAllArguments,
            'SINTERSTORE' => $getKeyFromAllArguments,
            'SUNION' => $getKeyFromAllArguments,
            'SUNIONSTORE' => $getKeyFromAllArguments,
            'SISMEMBER' => $getKeyFromFirstArgument,
            'SMEMBERS' => $getKeyFromFirstArgument,
            'SSCAN' => $getKeyFromFirstArgument,
            'SPOP' => $getKeyFromFirstArgument,
            'SRANDMEMBER' => $getKeyFromFirstArgument,
            'SREM' => $getKeyFromFirstArgument,

            /* commands operating on sorted sets */
            'ZADD' => $getKeyFromFirstArgument,
            'ZCARD' => $getKeyFromFirstArgument,
            'ZCOUNT' => $getKeyFromFirstArgument,
            'ZINCRBY' => $getKeyFromFirstArgument,
            'ZINTERSTORE' => [$this, 'getKeyFromZsetAggregationCommands'],
            'ZRANGE' => $getKeyFromFirstArgument,
            'ZRANGEBYSCORE' => $getKeyFromFirstArgument,
            'ZRANK' => $getKeyFromFirstArgument,
            'ZREM' => $getKeyFromFirstArgument,
            'ZREMRANGEBYRANK' => $getKeyFromFirstArgument,
            'ZREMRANGEBYSCORE' => $getKeyFromFirstArgument,
            'ZREVRANGE' => $getKeyFromFirstArgument,
            'ZREVRANGEBYSCORE' => $getKeyFromFirstArgument,
            'ZREVRANK' => $getKeyFromFirstArgument,
            'ZSCORE' => $getKeyFromFirstArgument,
            'ZUNIONSTORE' => [$this, 'getKeyFromZsetAggregationCommands'],
            'ZSCAN' => $getKeyFromFirstArgument,
            'ZLEXCOUNT' => $getKeyFromFirstArgument,
            'ZRANGEBYLEX' => $getKeyFromFirstArgument,
            'ZREMRANGEBYLEX' => $getKeyFromFirstArgument,
            'ZREVRANGEBYLEX' => $getKeyFromFirstArgument,

            /* commands operating on hashes */
            'HDEL' => $getKeyFromFirstArgument,
            'HEXISTS' => $getKeyFromFirstArgument,
            'HGET' => $getKeyFromFirstArgument,
            'HGETALL' => $getKeyFromFirstArgument,
            'HMGET' => $getKeyFromFirstArgument,
            'HMSET' => $getKeyFromFirstArgument,
            'HINCRBY' => $getKeyFromFirstArgument,
            'HINCRBYFLOAT' => $getKeyFromFirstArgument,
            'HKEYS' => $getKeyFromFirstArgument,
            'HLEN' => $getKeyFromFirstArgument,
            'HSET' => $getKeyFromFirstArgument,
            'HSETNX' => $getKeyFromFirstArgument,
            'HVALS' => $getKeyFromFirstArgument,
            'HSCAN' => $getKeyFromFirstArgument,
            'HSTRLEN' => $getKeyFromFirstArgument,

            /* commands operating on HyperLogLog */
            'PFADD' => $getKeyFromFirstArgument,
            'PFCOUNT' => $getKeyFromAllArguments,
            'PFMERGE' => $getKeyFromAllArguments,

            /* scripting */
            'EVAL' => [$this, 'getKeyFromScriptingCommands'],
            'EVALSHA' => [$this, 'getKeyFromScriptingCommands'],

            /* server */
            'INFO' => [$this, 'getFakeKey'],

            /* commands performing geospatial operations */
            'GEOADD' => $getKeyFromFirstArgument,
            'GEOHASH' => $getKeyFromFirstArgument,
            'GEOPOS' => $getKeyFromFirstArgument,
            'GEODIST' => $getKeyFromFirstArgument,
            'GEORADIUS' => [$this, 'getKeyFromGeoradiusCommands'],
            'GEORADIUSBYMEMBER' => [$this, 'getKeyFromGeoradiusCommands'],

            /* cluster */
            'CLUSTER' => [$this, 'getFakeKey'],
        ];
    }

    /**
     * Returns the list of IDs for the supported commands.
     *
     * @return array
     */
    public function getSupportedCommands()
    {
        return array_keys($this->commands);
    }

    /**
     * Sets an handler for the specified command ID.
     *
     * The signature of the callback must have a single parameter of type
     * Predis\Command\CommandInterface.
     *
     * When the callback argument is omitted or NULL, the previously associated
     * handler for the specified command ID is removed.
     *
     * @param string $commandID Command ID.
     * @param mixed  $callback  A valid callable object, or NULL to unset the handler.
     *
     * @throws InvalidArgumentException
     */
    public function setCommandHandler($commandID, $callback = null)
    {
        $commandID = strtoupper($commandID);

        if (!isset($callback)) {
            unset($this->commands[$commandID]);

            return;
        }

        if (!is_callable($callback)) {
            throw new InvalidArgumentException(
                'The argument must be a callable object or NULL.'
            );
        }

        $this->commands[$commandID] = $callback;
    }

    /**
     * Get fake key for commands with no key argument.
     *
     * @return string
     */
    protected function getFakeKey(): string
    {
        return 'key';
    }

    /**
     * Extracts the key from the first argument of a command instance.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return string
     */
    protected function getKeyFromFirstArgument(CommandInterface $command)
    {
        return $command->getArgument(0);
    }

    /**
     * Extracts the key from a command with multiple keys only when all keys in
     * the arguments array produce the same hash.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return string|null
     */
    protected function getKeyFromAllArguments(CommandInterface $command)
    {
        $arguments = $command->getArguments();

        if (!$this->checkSameSlotForKeys($arguments)) {
            return null;
        }

        return $arguments[0];
    }

    /**
     * Extracts the key from a command with multiple keys only when all keys in
     * the arguments array produce the same hash.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return string|null
     */
    protected function getKeyFromInterleavedArguments(CommandInterface $command)
    {
        $arguments = $command->getArguments();
        $keys = [];

        for ($i = 0; $i < count($arguments); $i += 2) {
            $keys[] = $arguments[$i];
        }

        if (!$this->checkSameSlotForKeys($keys)) {
            return null;
        }

        return $arguments[0];
    }

    /**
     * Extracts the key from SORT command.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return string|null
     */
    protected function getKeyFromSortCommand(CommandInterface $command)
    {
        $arguments = $command->getArguments();
        $firstKey = $arguments[0];

        if (1 === $argc = count($arguments)) {
            return $firstKey;
        }

        $keys = [$firstKey];

        for ($i = 1; $i < $argc; ++$i) {
            if (strtoupper($arguments[$i]) === 'STORE') {
                $keys[] = $arguments[++$i];
            }
        }

        if (!$this->checkSameSlotForKeys($keys)) {
            return null;
        }

        return $firstKey;
    }

    /**
     * Extracts the key from BLPOP and BRPOP commands.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return string|null
     */
    protected function getKeyFromBlockingListCommands(CommandInterface $command)
    {
        $arguments = $command->getArguments();

        if (!$this->checkSameSlotForKeys(array_slice($arguments, 0, count($arguments) - 1))) {
            return null;
        }

        return $arguments[0];
    }

    /**
     * Extracts the key from BITOP command.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return string|null
     */
    protected function getKeyFromBitOp(CommandInterface $command)
    {
        $arguments = $command->getArguments();

        if (!$this->checkSameSlotForKeys(array_slice($arguments, 1, count($arguments)))) {
            return null;
        }

        return $arguments[1];
    }

    /**
     * Extracts the key from GEORADIUS and GEORADIUSBYMEMBER commands.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return string|null
     */
    protected function getKeyFromGeoradiusCommands(CommandInterface $command)
    {
        $arguments = $command->getArguments();
        $argc = count($arguments);
        $startIndex = $command->getId() === 'GEORADIUS' ? 5 : 4;

        if ($argc > $startIndex) {
            $keys = [$arguments[0]];

            for ($i = $startIndex; $i < $argc; ++$i) {
                $argument = strtoupper($arguments[$i]);
                if ($argument === 'STORE' || $argument === 'STOREDIST') {
                    $keys[] = $arguments[++$i];
                }
            }

            if (!$this->checkSameSlotForKeys($keys)) {
                return null;
            }
        }

        return $arguments[0];
    }

    /**
     * Extracts the key from ZINTERSTORE and ZUNIONSTORE commands.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return string|null
     */
    protected function getKeyFromZsetAggregationCommands(CommandInterface $command)
    {
        $arguments = $command->getArguments();
        $keys = array_merge([$arguments[0]], array_slice($arguments, 2, $arguments[1]));

        if (!$this->checkSameSlotForKeys($keys)) {
            return null;
        }

        return $arguments[0];
    }

    /**
     * Extracts the key from EVAL and EVALSHA commands.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return string|null
     */
    protected function getKeyFromScriptingCommands(CommandInterface $command)
    {
        $keys = $command instanceof ScriptCommand
            ? $command->getKeys()
            : array_slice($args = $command->getArguments(), 2, $args[1]);

        if (!$keys || !$this->checkSameSlotForKeys($keys)) {
            return null;
        }

        return $keys[0];
    }

    /**
     * {@inheritdoc}
     */
    public function getSlot(CommandInterface $command)
    {
        $slot = $command->getSlot();

        if (!isset($slot) && isset($this->commands[$cmdID = $command->getId()])) {
            $key = call_user_func($this->commands[$cmdID], $command);

            if (isset($key)) {
                $slot = $this->getSlotByKey($key);
                $command->setSlot($slot);
            }
        }

        return $slot;
    }

    /**
     * Checks if the specified array of keys will generate the same hash.
     *
     * @param array $keys Array of keys.
     *
     * @return bool
     */
    protected function checkSameSlotForKeys(array $keys)
    {
        if (!$count = count($keys)) {
            return false;
        }

        $currentSlot = $this->getSlotByKey($keys[0]);

        for ($i = 1; $i < $count; ++$i) {
            $nextSlot = $this->getSlotByKey($keys[$i]);

            if ($currentSlot !== $nextSlot) {
                return false;
            }

            $currentSlot = $nextSlot;
        }

        return true;
    }

    /**
     * Returns only the hashable part of a key (delimited by "{...}"), or the
     * whole key if a key tag is not found in the string.
     *
     * @param string $key A key.
     *
     * @return string
     */
    protected function extractKeyTag($key)
    {
        if (false !== $start = strpos($key, '{')) {
            if (false !== ($end = strpos($key, '}', $start)) && $end !== ++$start) {
                $key = substr($key, $start, $end - $start);
            }
        }

        return $key;
    }
}
                                                                                                                                                                                                                                predis/src/Cluster/RedisStrategy.php                                                                0000644                 00000002372 15233650113 0013547 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 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 Predis\Cluster\Hash\CRC16;
use Predis\Cluster\Hash\HashGeneratorInterface;
use Predis\NotSupportedException;

/**
 * Default class used by Predis to calculate hashes out of keys of
 * commands supported by redis-cluster.
 */
class RedisStrategy extends ClusterStrategy
{
    protected $hashGenerator;

    /**
     * @param HashGeneratorInterface $hashGenerator Hash generator instance.
     */
    public function __construct(HashGeneratorInterface $hashGenerator = null)
    {
        parent::__construct();

        $this->hashGenerator = $hashGenerator ?: new CRC16();
    }

    /**
     * {@inheritdoc}
     */
    public function getSlotByKey($key)
    {
        $key = $this->extractKeyTag($key);

        return $this->hashGenerator->hash($key) & 0x3FFF;
    }

    /**
     * {@inheritdoc}
     */
    public function getDistributor()
    {
        $class = get_class($this);
        throw new NotSupportedException("$class does not provide an external distributor");
    }
}
                                                                                                                                                                                                                                                                      predis/src/Cluster/Distributor/EmptyRingException.php                                               0000644                 00000000637 15233650113 0017067 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 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\Distributor;

use Exception;

/**
 * Exception class that identifies empty rings.
 */
class EmptyRingException extends Exception
{
}
                                                                                                 predis/src/Cluster/Distributor/KetamaRing.php                                                       0000644                 00000003545 15233650113 0015315 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 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\Distributor;

/**
 * This class implements an hashring-based distributor that uses the same
 * algorithm of libketama to distribute keys in a cluster using client-side
 * sharding.
 * @author Lorenzo Castelli <lcastelli@gmail.com>
 */
class KetamaRing extends HashRing
{
    public const DEFAULT_REPLICAS = 160;

    /**
     * @param mixed $nodeHashCallback Callback returning a string used to calculate the hash of nodes.
     */
    public function __construct($nodeHashCallback = null)
    {
        parent::__construct($this::DEFAULT_REPLICAS, $nodeHashCallback);
    }

    /**
     * {@inheritdoc}
     */
    protected function addNodeToRing(&$ring, $node, $totalNodes, $replicas, $weightRatio)
    {
        $nodeObject = $node['object'];
        $nodeHash = $this->getNodeHash($nodeObject);
        $replicas = (int) floor($weightRatio * $totalNodes * ($replicas / 4));

        for ($i = 0; $i < $replicas; ++$i) {
            $unpackedDigest = unpack('V4', md5("$nodeHash-$i", true));

            foreach ($unpackedDigest as $key) {
                $ring[$key] = $nodeObject;
            }
        }
    }

    /**
     * {@inheritdoc}
     */
    public function hash($value)
    {
        $hash = unpack('V', md5($value, true));

        return $hash[1];
    }

    /**
     * {@inheritdoc}
     */
    protected function wrapAroundStrategy($upper, $lower, $ringKeysCount)
    {
        // Binary search for the first item in ringkeys with a value greater
        // or equal to the key. If no such item exists, return the first item.
        return $lower < $ringKeysCount ? $lower : 0;
    }
}
                                                                                                                                                           predis/src/Cluster/Distributor/HashRing.php                                                         0000644                 00000015241 15233650113 0014772 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 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\Distributor;

use Predis\Cluster\Hash\HashGeneratorInterface;

/**
 * This class implements an hashring-based distributor that uses the same
 * algorithm of memcache to distribute keys in a cluster using client-side
 * sharding.
 * @author Lorenzo Castelli <lcastelli@gmail.com>
 */
class HashRing implements DistributorInterface, HashGeneratorInterface
{
    public const DEFAULT_REPLICAS = 128;
    public const DEFAULT_WEIGHT = 100;

    private $ring;
    private $ringKeys;
    private $ringKeysCount;
    private $replicas;
    private $nodeHashCallback;
    private $nodes = [];

    /**
     * @param int   $replicas         Number of replicas in the ring.
     * @param mixed $nodeHashCallback Callback returning a string used to calculate the hash of nodes.
     */
    public function __construct($replicas = self::DEFAULT_REPLICAS, $nodeHashCallback = null)
    {
        $this->replicas = $replicas;
        $this->nodeHashCallback = $nodeHashCallback;
    }

    /**
     * Adds a node to the ring with an optional weight.
     *
     * @param mixed $node   Node object.
     * @param int   $weight Weight for the node.
     */
    public function add($node, $weight = null)
    {
        // In case of collisions in the hashes of the nodes, the node added
        // last wins, thus the order in which nodes are added is significant.
        $this->nodes[] = [
            'object' => $node,
            'weight' => (int) $weight ?: $this::DEFAULT_WEIGHT,
        ];

        $this->reset();
    }

    /**
     * {@inheritdoc}
     */
    public function remove($node)
    {
        // A node is removed by resetting the ring so that it's recreated from
        // scratch, in order to reassign possible hashes with collisions to the
        // right node according to the order in which they were added in the
        // first place.
        for ($i = 0; $i < count($this->nodes); ++$i) {
            if ($this->nodes[$i]['object'] === $node) {
                array_splice($this->nodes, $i, 1);
                $this->reset();

                break;
            }
        }
    }

    /**
     * Resets the distributor.
     */
    private function reset()
    {
        unset(
            $this->ring,
            $this->ringKeys,
            $this->ringKeysCount
        );
    }

    /**
     * Returns the initialization status of the distributor.
     *
     * @return bool
     */
    private function isInitialized()
    {
        return isset($this->ringKeys);
    }

    /**
     * Calculates the total weight of all the nodes in the distributor.
     *
     * @return int
     */
    private function computeTotalWeight()
    {
        $totalWeight = 0;

        foreach ($this->nodes as $node) {
            $totalWeight += $node['weight'];
        }

        return $totalWeight;
    }

    /**
     * Initializes the distributor.
     */
    private function initialize()
    {
        if ($this->isInitialized()) {
            return;
        }

        if (!$this->nodes) {
            throw new EmptyRingException('Cannot initialize an empty hashring.');
        }

        $this->ring = [];
        $totalWeight = $this->computeTotalWeight();
        $nodesCount = count($this->nodes);

        foreach ($this->nodes as $node) {
            $weightRatio = $node['weight'] / $totalWeight;
            $this->addNodeToRing($this->ring, $node, $nodesCount, $this->replicas, $weightRatio);
        }

        ksort($this->ring, SORT_NUMERIC);
        $this->ringKeys = array_keys($this->ring);
        $this->ringKeysCount = count($this->ringKeys);
    }

    /**
     * Implements the logic needed to add a node to the hashring.
     *
     * @param array $ring        Source hashring.
     * @param mixed $node        Node object to be added.
     * @param int   $totalNodes  Total number of nodes.
     * @param int   $replicas    Number of replicas in the ring.
     * @param float $weightRatio Weight ratio for the node.
     */
    protected function addNodeToRing(&$ring, $node, $totalNodes, $replicas, $weightRatio)
    {
        $nodeObject = $node['object'];
        $nodeHash = $this->getNodeHash($nodeObject);
        $replicas = (int) round($weightRatio * $totalNodes * $replicas);

        for ($i = 0; $i < $replicas; ++$i) {
            $key = $this->hash("$nodeHash:$i");
            $ring[$key] = $nodeObject;
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function getNodeHash($nodeObject)
    {
        if (!isset($this->nodeHashCallback)) {
            return (string) $nodeObject;
        }

        return call_user_func($this->nodeHashCallback, $nodeObject);
    }

    /**
     * {@inheritdoc}
     */
    public function hash($value)
    {
        return crc32($value);
    }

    /**
     * {@inheritdoc}
     */
    public function getByHash($hash)
    {
        return $this->ring[$this->getSlot($hash)];
    }

    /**
     * {@inheritdoc}
     */
    public function getBySlot($slot)
    {
        $this->initialize();

        if (isset($this->ring[$slot])) {
            return $this->ring[$slot];
        }
    }

    /**
     * {@inheritdoc}
     */
    public function getSlot($hash)
    {
        $this->initialize();

        $ringKeys = $this->ringKeys;
        $upper = $this->ringKeysCount - 1;
        $lower = 0;

        while ($lower <= $upper) {
            $index = ($lower + $upper) >> 1;
            $item = $ringKeys[$index];

            if ($item > $hash) {
                $upper = $index - 1;
            } elseif ($item < $hash) {
                $lower = $index + 1;
            } else {
                return $item;
            }
        }

        return $ringKeys[$this->wrapAroundStrategy($upper, $lower, $this->ringKeysCount)];
    }

    /**
     * {@inheritdoc}
     */
    public function get($value)
    {
        $hash = $this->hash($value);

        return $this->getByHash($hash);
    }

    /**
     * Implements a strategy to deal with wrap-around errors during binary searches.
     *
     * @param int $upper
     * @param int $lower
     * @param int $ringKeysCount
     *
     * @return int
     */
    protected function wrapAroundStrategy($upper, $lower, $ringKeysCount)
    {
        // Binary search for the last item in ringkeys with a value less or
        // equal to the key. If no such item exists, return the last item.
        return $upper >= 0 ? $upper : $ringKeysCount - 1;
    }

    /**
     * {@inheritdoc}
     */
    public function getHashGenerator()
    {
        return $this;
    }
}
                                                                                                                                                                                                                                                                                                                                                               predis/src/Cluster/Distributor/DistributorInterface.php                                             0000644                 00000003444 15233650113 0017424 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 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\Distributor;

use Predis\Cluster\Hash\HashGeneratorInterface;

/**
 * A distributor implements the logic to automatically distribute keys among
 * several nodes for client-side sharding.
 */
interface DistributorInterface
{
    /**
     * Adds a node to the distributor with an optional weight.
     *
     * @param mixed $node   Node object.
     * @param int   $weight Weight for the node.
     */
    public function add($node, $weight = null);

    /**
     * Removes a node from the distributor.
     *
     * @param mixed $node Node object.
     */
    public function remove($node);

    /**
     * Returns the corresponding slot of a node from the distributor using the
     * computed hash of a key.
     *
     * @param mixed $hash
     *
     * @return mixed
     */
    public function getSlot($hash);

    /**
     * Returns a node from the distributor using its assigned slot ID.
     *
     * @param mixed $slot
     *
     * @return mixed|null
     */
    public function getBySlot($slot);

    /**
     * Returns a node from the distributor using the computed hash of a key.
     *
     * @param mixed $hash
     *
     * @return mixed
     */
    public function getByHash($hash);

    /**
     * Returns a node from the distributor mapping to the specified value.
     *
     * @param string $value
     *
     * @return mixed
     */
    public function get($value);

    /**
     * Returns the underlying hash generator instance.
     *
     * @return HashGeneratorInterface
     */
    public function getHashGenerator();
}
                                                                                                                                                                                                                            predis/src/Cluster/SlotMap.php                                                                      0000644                 00000011413 15233650113 0012331 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 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 SlotMap 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);
    }
}
                                                                                                                                                                                                                                                     predis/src/Cluster/PredisStrategy.php                                                               0000644                 00000003175 15233650113 0013731 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 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 Predis\Cluster\Distributor\DistributorInterface;
use Predis\Cluster\Distributor\HashRing;

/**
 * Default cluster strategy used by Predis to handle client-side sharding.
 */
class PredisStrategy extends ClusterStrategy
{
    protected $distributor;

    /**
     * @param DistributorInterface $distributor Optional distributor instance.
     */
    public function __construct(DistributorInterface $distributor = null)
    {
        parent::__construct();

        $this->distributor = $distributor ?: new HashRing();
    }

    /**
     * {@inheritdoc}
     */
    public function getSlotByKey($key)
    {
        $key = $this->extractKeyTag($key);
        $hash = $this->distributor->hash($key);

        return $this->distributor->getSlot($hash);
    }

    /**
     * {@inheritdoc}
     */
    protected function checkSameSlotForKeys(array $keys)
    {
        if (!$count = count($keys)) {
            return false;
        }

        $currentKey = $this->extractKeyTag($keys[0]);

        for ($i = 1; $i < $count; ++$i) {
            $nextKey = $this->extractKeyTag($keys[$i]);

            if ($currentKey !== $nextKey) {
                return false;
            }

            $currentKey = $nextKey;
        }

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function getDistributor()
    {
        return $this->distributor;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                   predis/src/Transaction/MultiExecState.php                                                           0000644                 00000005735 15233650113 0014530 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Transaction;

/**
 * Utility class used to track the state of a MULTI / EXEC transaction.
 */
class MultiExecState
{
    public const INITIALIZED = 1;    // 0b00001
    public const INSIDEBLOCK = 2;    // 0b00010
    public const DISCARDED = 4;    // 0b00100
    public const CAS = 8;    // 0b01000
    public const WATCH = 16;   // 0b10000

    private $flags;

    public function __construct()
    {
        $this->flags = 0;
    }

    /**
     * Sets the internal state flags.
     *
     * @param int $flags Set of flags
     */
    public function set($flags)
    {
        $this->flags = $flags;
    }

    /**
     * Gets the internal state flags.
     *
     * @return int
     */
    public function get()
    {
        return $this->flags;
    }

    /**
     * Sets one or more flags.
     *
     * @param int $flags Set of flags
     */
    public function flag($flags)
    {
        $this->flags |= $flags;
    }

    /**
     * Resets one or more flags.
     *
     * @param int $flags Set of flags
     */
    public function unflag($flags)
    {
        $this->flags &= ~$flags;
    }

    /**
     * Returns if the specified flag or set of flags is set.
     *
     * @param int $flags Flag
     *
     * @return bool
     */
    public function check($flags)
    {
        return ($this->flags & $flags) === $flags;
    }

    /**
     * Resets the state of a transaction.
     */
    public function reset()
    {
        $this->flags = 0;
    }

    /**
     * Returns the state of the RESET flag.
     *
     * @return bool
     */
    public function isReset()
    {
        return $this->flags === 0;
    }

    /**
     * Returns the state of the INITIALIZED flag.
     *
     * @return bool
     */
    public function isInitialized()
    {
        return $this->check(self::INITIALIZED);
    }

    /**
     * Returns the state of the INSIDEBLOCK flag.
     *
     * @return bool
     */
    public function isExecuting()
    {
        return $this->check(self::INSIDEBLOCK);
    }

    /**
     * Returns the state of the CAS flag.
     *
     * @return bool
     */
    public function isCAS()
    {
        return $this->check(self::CAS);
    }

    /**
     * Returns if WATCH is allowed in the current state.
     *
     * @return bool
     */
    public function isWatchAllowed()
    {
        return $this->check(self::INITIALIZED) && !$this->check(self::CAS);
    }

    /**
     * Returns the state of the WATCH flag.
     *
     * @return bool
     */
    public function isWatching()
    {
        return $this->check(self::WATCH);
    }

    /**
     * Returns the state of the DISCARDED flag.
     *
     * @return bool
     */
    public function isDiscarded()
    {
        return $this->check(self::DISCARDED);
    }
}
                                   predis/src/Transaction/MultiExec.php                                                                0000644                 00000033173 15233650113 0013524 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Transaction;

use Exception;
use InvalidArgumentException;
use Predis\ClientContextInterface;
use Predis\ClientException;
use Predis\ClientInterface;
use Predis\Command\CommandInterface;
use Predis\CommunicationException;
use Predis\Connection\Cluster\ClusterInterface;
use Predis\Connection\RelayConnection;
use Predis\NotSupportedException;
use Predis\Protocol\ProtocolException;
use Predis\Response\Error;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\ServerException;
use Predis\Response\Status as StatusResponse;
use Relay\Exception as RelayException;
use Relay\Relay;
use SplQueue;

/**
 * Client-side abstraction of a Redis transaction based on MULTI / EXEC.
 *
 * {@inheritdoc}
 */
class MultiExec implements ClientContextInterface
{
    private $state;

    protected $client;
    protected $commands;
    protected $exceptions = true;
    protected $attempts = 0;
    protected $watchKeys = [];
    protected $modeCAS = false;

    /**
     * @param ClientInterface $client  Client instance used by the transaction.
     * @param array           $options Initialization options.
     */
    public function __construct(ClientInterface $client, array $options = null)
    {
        $this->assertClient($client);

        $this->client = $client;
        $this->state = new MultiExecState();

        $this->configure($client, $options ?: []);
        $this->reset();
    }

    /**
     * Checks if the passed client instance satisfies the required conditions
     * needed to initialize the transaction object.
     *
     * @param ClientInterface $client Client instance used by the transaction object.
     *
     * @throws NotSupportedException
     */
    private function assertClient(ClientInterface $client)
    {
        if ($client->getConnection() instanceof ClusterInterface) {
            throw new NotSupportedException(
                'Cannot initialize a MULTI/EXEC transaction over cluster connections.'
            );
        }

        if (!$client->getCommandFactory()->supports('MULTI', 'EXEC', 'DISCARD')) {
            throw new NotSupportedException(
                'MULTI, EXEC and DISCARD are not supported by the current command factory.'
            );
        }
    }

    /**
     * Configures the transaction using the provided options.
     *
     * @param ClientInterface $client  Underlying client instance.
     * @param array           $options Array of options for the transaction.
     **/
    protected function configure(ClientInterface $client, array $options)
    {
        if (isset($options['exceptions'])) {
            $this->exceptions = (bool) $options['exceptions'];
        } else {
            $this->exceptions = $client->getOptions()->exceptions;
        }

        if (isset($options['cas'])) {
            $this->modeCAS = (bool) $options['cas'];
        }

        if (isset($options['watch']) && $keys = $options['watch']) {
            $this->watchKeys = $keys;
        }

        if (isset($options['retry'])) {
            $this->attempts = (int) $options['retry'];
        }
    }

    /**
     * Resets the state of the transaction.
     */
    protected function reset()
    {
        $this->state->reset();
        $this->commands = new SplQueue();
    }

    /**
     * Initializes the transaction context.
     */
    protected function initialize()
    {
        if ($this->state->isInitialized()) {
            return;
        }

        if ($this->modeCAS) {
            $this->state->flag(MultiExecState::CAS);
        }

        if ($this->watchKeys) {
            $this->watch($this->watchKeys);
        }

        $cas = $this->state->isCAS();
        $discarded = $this->state->isDiscarded();

        if (!$cas || ($cas && $discarded)) {
            $this->call('MULTI');

            if ($discarded) {
                $this->state->unflag(MultiExecState::CAS);
            }
        }

        $this->state->unflag(MultiExecState::DISCARDED);
        $this->state->flag(MultiExecState::INITIALIZED);
    }

    /**
     * Dynamically invokes a Redis command with the specified arguments.
     *
     * @param string $method    Command ID.
     * @param array  $arguments Arguments for the command.
     *
     * @return mixed
     */
    public function __call($method, $arguments)
    {
        return $this->executeCommand(
            $this->client->createCommand($method, $arguments)
        );
    }

    /**
     * Executes a Redis command bypassing the transaction logic.
     *
     * @param string $commandID Command ID.
     * @param array  $arguments Arguments for the command.
     *
     * @return mixed
     * @throws ServerException
     */
    protected function call($commandID, array $arguments = [])
    {
        try {
            $response = $this->client->executeCommand(
                $this->client->createCommand($commandID, $arguments)
            );
        } catch (ServerException $exception) {
            if (!$this->client->getConnection() instanceof RelayConnection) {
                throw $exception;
            }

            if (strcasecmp($commandID, 'EXEC') != 0) {
                throw $exception;
            }

            if (!strpos($exception->getMessage(), 'RELAY_ERR_REDIS')) {
                throw $exception;
            }

            return null;
        }

        if ($response instanceof ErrorResponseInterface) {
            throw new ServerException($response->getMessage());
        }

        return $response;
    }

    /**
     * Executes the specified Redis command.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return $this|mixed
     * @throws AbortedMultiExecException
     * @throws CommunicationException
     */
    public function executeCommand(CommandInterface $command)
    {
        $this->initialize();

        if ($this->state->isCAS()) {
            return $this->client->executeCommand($command);
        }

        $response = $this->client->getConnection()->executeCommand($command);

        if ($response instanceof StatusResponse && $response == 'QUEUED') {
            $this->commands->enqueue($command);
        } elseif ($response instanceof Relay) {
            $this->commands->enqueue($command);
        } elseif ($response instanceof ErrorResponseInterface) {
            throw new AbortedMultiExecException($this, $response->getMessage());
        } else {
            $this->onProtocolError('The server did not return a +QUEUED status response.');
        }

        return $this;
    }

    /**
     * Executes WATCH against one or more keys.
     *
     * @param string|array $keys One or more keys.
     *
     * @return mixed
     * @throws NotSupportedException
     * @throws ClientException
     */
    public function watch($keys)
    {
        if (!$this->client->getCommandFactory()->supports('WATCH')) {
            throw new NotSupportedException('WATCH is not supported by the current command factory.');
        }

        if ($this->state->isWatchAllowed()) {
            throw new ClientException('Sending WATCH after MULTI is not allowed.');
        }

        $response = $this->call('WATCH', is_array($keys) ? $keys : [$keys]);
        $this->state->flag(MultiExecState::WATCH);

        return $response;
    }

    /**
     * Finalizes the transaction by executing MULTI on the server.
     *
     * @return MultiExec
     */
    public function multi()
    {
        if ($this->state->check(MultiExecState::INITIALIZED | MultiExecState::CAS)) {
            $this->state->unflag(MultiExecState::CAS);
            $this->call('MULTI');
        } else {
            $this->initialize();
        }

        return $this;
    }

    /**
     * Executes UNWATCH.
     *
     * @return MultiExec
     * @throws NotSupportedException
     */
    public function unwatch()
    {
        if (!$this->client->getCommandFactory()->supports('UNWATCH')) {
            throw new NotSupportedException(
                'UNWATCH is not supported by the current command factory.'
            );
        }

        $this->state->unflag(MultiExecState::WATCH);
        $this->__call('UNWATCH', []);

        return $this;
    }

    /**
     * Resets the transaction by UNWATCH-ing the keys that are being WATCHed and
     * DISCARD-ing pending commands that have been already sent to the server.
     *
     * @return MultiExec
     */
    public function discard()
    {
        if ($this->state->isInitialized()) {
            $this->call($this->state->isCAS() ? 'UNWATCH' : 'DISCARD');

            $this->reset();
            $this->state->flag(MultiExecState::DISCARDED);
        }

        return $this;
    }

    /**
     * Executes the whole transaction.
     *
     * @return mixed
     */
    public function exec()
    {
        return $this->execute();
    }

    /**
     * Checks the state of the transaction before execution.
     *
     * @param mixed $callable Callback for execution.
     *
     * @throws InvalidArgumentException
     * @throws ClientException
     */
    private function checkBeforeExecution($callable)
    {
        if ($this->state->isExecuting()) {
            throw new ClientException(
                'Cannot invoke "execute" or "exec" inside an active transaction context.'
            );
        }

        if ($callable) {
            if (!is_callable($callable)) {
                throw new InvalidArgumentException('The argument must be a callable object.');
            }

            if (!$this->commands->isEmpty()) {
                $this->discard();

                throw new ClientException(
                    'Cannot execute a transaction block after using fluent interface.'
                );
            }
        } elseif ($this->attempts) {
            $this->discard();

            throw new ClientException(
                'Automatic retries are supported only when a callable block is provided.'
            );
        }
    }

    /**
     * Handles the actual execution of the whole transaction.
     *
     * @param mixed $callable Optional callback for execution.
     *
     * @return array
     * @throws CommunicationException
     * @throws AbortedMultiExecException
     * @throws ServerException
     */
    public function execute($callable = null)
    {
        $this->checkBeforeExecution($callable);

        $execResponse = null;
        $attempts = $this->attempts;

        do {
            if ($callable) {
                $this->executeTransactionBlock($callable);
            }

            if ($this->commands->isEmpty()) {
                if ($this->state->isWatching()) {
                    $this->discard();
                }

                return;
            }

            $execResponse = $this->call('EXEC');

            // The additional `false` check is needed for Relay,
            // let's hope it won't break anything
            if ($execResponse === null || $execResponse === false) {
                if ($attempts === 0) {
                    throw new AbortedMultiExecException(
                        $this, 'The current transaction has been aborted by the server.'
                    );
                }

                $this->reset();

                continue;
            }

            break;
        } while ($attempts-- > 0);

        $response = [];
        $commands = $this->commands;
        $size = count($execResponse);

        if ($size !== count($commands)) {
            $this->onProtocolError('EXEC returned an unexpected number of response items.');
        }

        for ($i = 0; $i < $size; ++$i) {
            $cmdResponse = $execResponse[$i];

            if ($this->exceptions && $cmdResponse instanceof ErrorResponseInterface) {
                throw new ServerException($cmdResponse->getMessage());
            }

            if ($cmdResponse instanceof RelayException) {
                if ($this->exceptions) {
                    throw new ServerException($cmdResponse->getMessage(), $cmdResponse->getCode(), $cmdResponse);
                }

                $commands->dequeue();
                $response[$i] = new Error($cmdResponse->getMessage());
                continue;
            }

            $response[$i] = $commands->dequeue()->parseResponse($cmdResponse);
        }

        return $response;
    }

    /**
     * Passes the current transaction object to a callable block for execution.
     *
     * @param mixed $callable Callback.
     *
     * @throws CommunicationException
     * @throws ServerException
     */
    protected function executeTransactionBlock($callable)
    {
        $exception = null;
        $this->state->flag(MultiExecState::INSIDEBLOCK);

        try {
            call_user_func($callable, $this);
        } catch (CommunicationException $exception) {
            // NOOP
        } catch (ServerException $exception) {
            // NOOP
        } catch (Exception $exception) {
            $this->discard();
        }

        $this->state->unflag(MultiExecState::INSIDEBLOCK);

        if ($exception) {
            throw $exception;
        }
    }

    /**
     * Helper method for protocol errors encountered inside the transaction.
     *
     * @param string $message Error message.
     */
    private function onProtocolError($message)
    {
        // Since a MULTI/EXEC block cannot be initialized when using aggregate
        // connections we can safely assume that Predis\Client::getConnection()
        // will return a Predis\Connection\NodeConnectionInterface instance.
        CommunicationException::handle(new ProtocolException(
            $this->client->getConnection(), $message
        ));
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Transaction/AbortedMultiExecException.php                                                0000644                 00000002072 15233650113 0016676 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Transaction;

use Predis\PredisException;

/**
 * Exception class that identifies a MULTI / EXEC transaction aborted by Redis.
 */
class AbortedMultiExecException extends PredisException
{
    private $transaction;

    /**
     * @param MultiExec $transaction Transaction that generated the exception.
     * @param string    $message     Error message.
     * @param int       $code        Error code.
     */
    public function __construct(MultiExec $transaction, $message, $code = 0)
    {
        parent::__construct($message, is_null($code) ? 0 : $code);

        $this->transaction = $transaction;
    }

    /**
     * Returns the transaction that generated the exception.
     *
     * @return MultiExec
     */
    public function getTransaction()
    {
        return $this->transaction;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                      predis/src/Configuration/OptionsInterface.php                                                       0000644                 00000003660 15233650113 0015421 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Configuration;

use Predis\Command\Processor\ProcessorInterface;

/**
 * @property callable                            $aggregate   Custom aggregate connection initializer
 * @property callable                            $cluster     Aggregate connection initializer for clustering
 * @property \Predis\Connection\FactoryInterface $connections Connection factory for creating new connections
 * @property bool                                $exceptions  Toggles exceptions in client for -ERR responses
 * @property ProcessorInterface                  $prefix      Key prefixing strategy using the supplied string as prefix
 * @property \Predis\Command\FactoryInterface    $commands    Command factory for creating Redis commands
 * @property callable                            $replication Aggregate connection initializer for replication
 */
interface OptionsInterface
{
    /**
     * Returns the default value for the given option.
     *
     * @param string $option Name of the option
     *
     * @return mixed|null
     */
    public function getDefault($option);

    /**
     * Checks if the given option has been set by the user upon initialization.
     *
     * @param string $option Name of the option
     *
     * @return bool
     */
    public function defined($option);

    /**
     * Checks if the given option has been set and does not evaluate to NULL.
     *
     * @param string $option Name of the option
     *
     * @return bool
     */
    public function __isset($option);

    /**
     * Returns the value of the given option.
     *
     * @param string $option Name of the option
     *
     * @return mixed|null
     */
    public function __get($option);
}
                                                                                predis/src/Configuration/Options.php                                                                0000644                 00000005663 15233650113 0013605 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Configuration;

/**
 * Default client options container for Predis\Client.
 *
 * Pre-defined options have their specialized handlers that can filter, convert
 * an lazily initialize values in a mini-DI container approach.
 *
 * {@inheritdoc}
 */
class Options implements OptionsInterface
{
    /** @var array */
    protected $handlers = [
        'aggregate' => Option\Aggregate::class,
        'cluster' => Option\Cluster::class,
        'replication' => Option\Replication::class,
        'connections' => Option\Connections::class,
        'commands' => Option\Commands::class,
        'exceptions' => Option\Exceptions::class,
        'prefix' => Option\Prefix::class,
        'crc16' => Option\CRC16::class,
    ];

    /** @var array */
    protected $options = [];

    /** @var array */
    protected $input;

    /**
     * @param array $options Named array of client options
     */
    public function __construct(array $options = null)
    {
        $this->input = $options ?? [];
    }

    /**
     * {@inheritdoc}
     */
    public function getDefault($option)
    {
        if (isset($this->handlers[$option])) {
            $handler = $this->handlers[$option];
            $handler = new $handler();

            return $handler->getDefault($this);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function defined($option)
    {
        return
            array_key_exists($option, $this->options)
            || array_key_exists($option, $this->input)
        ;
    }

    /**
     * {@inheritdoc}
     */
    public function __isset($option)
    {
        return (
            array_key_exists($option, $this->options)
            || array_key_exists($option, $this->input)
        ) && $this->__get($option) !== null;
    }

    /**
     * {@inheritdoc}
     */
    public function __get($option)
    {
        if (isset($this->options[$option]) || array_key_exists($option, $this->options)) {
            return $this->options[$option];
        }

        if (isset($this->input[$option]) || array_key_exists($option, $this->input)) {
            $value = $this->input[$option];
            unset($this->input[$option]);

            if (isset($this->handlers[$option])) {
                $handler = $this->handlers[$option];
                $handler = new $handler();
                $value = $handler->filter($this, $value);
            } elseif (is_object($value) && method_exists($value, '__invoke')) {
                $value = $value($this);
            }

            return $this->options[$option] = $value;
        }

        if (isset($this->handlers[$option])) {
            return $this->options[$option] = $this->getDefault($option);
        }

        return;
    }
}
                                                                             predis/src/Configuration/Option/Replication.php                                                     0000644                 00000007536 15233650113 0015674 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Configuration\Option;

use InvalidArgumentException;
use Predis\Configuration\OptionsInterface;
use Predis\Connection\AggregateConnectionInterface;
use Predis\Connection\Replication\MasterSlaveReplication;
use Predis\Connection\Replication\SentinelReplication;

/**
 * Configures an aggregate connection used for master/slave replication among
 * multiple Redis nodes.
 */
class Replication extends Aggregate
{
    /**
     * {@inheritdoc}
     */
    public function filter(OptionsInterface $options, $value)
    {
        if (is_string($value)) {
            $value = $this->getConnectionInitializerByString($options, $value);
        }

        if (is_callable($value)) {
            return $this->getConnectionInitializer($options, $value);
        } else {
            throw new InvalidArgumentException(sprintf(
                '%s expects either a string or a callable value, %s given',
                static::class,
                is_object($value) ? get_class($value) : gettype($value)
            ));
        }
    }

    /**
     * Returns a connection initializer (callable) from a descriptive string.
     *
     * Each connection initializer is specialized for the specified replication
     * backend so that all the necessary steps for the configuration of the new
     * aggregate connection are performed inside the initializer and the client
     * receives a ready-to-use connection.
     *
     * Supported configuration values are:
     *
     * - `predis` for unmanaged replication setups
     * - `redis-sentinel` for replication setups managed by redis-sentinel
     * - `sentinel` is an alias of `redis-sentinel`
     *
     * @param OptionsInterface $options     Client options
     * @param string           $description Identifier of a replication backend
     *
     * @return callable
     */
    protected function getConnectionInitializerByString(OptionsInterface $options, string $description)
    {
        switch ($description) {
            case 'sentinel':
            case 'redis-sentinel':
                return function ($parameters, $options) {
                    return new SentinelReplication($options->service, $parameters, $options->connections);
                };

            case 'predis':
                return $this->getDefaultConnectionInitializer();

            default:
                throw new InvalidArgumentException(sprintf(
                    '%s expects either `predis`, `sentinel` or `redis-sentinel` as valid string values, `%s` given',
                    static::class,
                    $description
                ));
        }
    }

    /**
     * Returns the default connection initializer.
     *
     * @return callable
     */
    protected function getDefaultConnectionInitializer()
    {
        return function ($parameters, $options) {
            $connection = new MasterSlaveReplication();

            if ($options->autodiscovery) {
                $connection->setConnectionFactory($options->connections);
                $connection->setAutoDiscovery(true);
            }

            return $connection;
        };
    }

    /**
     * {@inheritdoc}
     */
    public static function aggregate(OptionsInterface $options, AggregateConnectionInterface $connection, array $nodes)
    {
        if (!$connection instanceof SentinelReplication) {
            parent::aggregate($options, $connection, $nodes);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function getDefault(OptionsInterface $options)
    {
        return $this->getConnectionInitializer(
            $options,
            $this->getDefaultConnectionInitializer()
        );
    }
}
                                                                                                                                                                  predis/src/Configuration/Option/Aggregate.php                                                       0000644                 00000010020 15233650113 0015267 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Configuration\Option;

use InvalidArgumentException;
use Predis\Configuration\OptionInterface;
use Predis\Configuration\OptionsInterface;
use Predis\Connection\AggregateConnectionInterface;
use Predis\Connection\NodeConnectionInterface;

/**
 * Client option for configuring generic aggregate connections.
 *
 * The only value accepted by this option is a callable that must return a valid
 * connection instance of Predis\Connection\AggregateConnectionInterface when
 * invoked by the client to create a new aggregate connection instance.
 *
 * Creation and configuration of the aggregate connection is up to the user.
 */
class Aggregate implements OptionInterface
{
    /**
     * {@inheritdoc}
     */
    public function filter(OptionsInterface $options, $value)
    {
        if (!is_callable($value)) {
            throw new InvalidArgumentException(sprintf(
                '%s expects a callable object acting as an aggregate connection initializer',
                static::class
            ));
        }

        return $this->getConnectionInitializer($options, $value);
    }

    /**
     * Wraps a user-supplied callable used to create a new aggregate connection.
     *
     * When the original callable acting as a connection initializer is executed
     * by the client to create a new aggregate connection, it will receive the
     * following arguments:
     *
     * - $parameters (same as passed to Predis\Client::__construct())
     * - $options (options container, Predis\Configuration\OptionsInterface)
     * - $option (current option, Predis\Configuration\OptionInterface)
     *
     * The original callable must return a valid aggregation connection instance
     * of type Predis\Connection\AggregateConnectionInterface, this is enforced
     * by the wrapper returned by this method and an exception is thrown when
     * invalid values are returned.
     *
     * @param OptionsInterface $options  Client options
     * @param callable         $callable Callable initializer
     *
     * @return callable
     * @throws InvalidArgumentException
     */
    protected function getConnectionInitializer(OptionsInterface $options, callable $callable)
    {
        return function ($parameters = null, $autoaggregate = false) use ($callable, $options) {
            $connection = call_user_func_array($callable, [&$parameters, $options, $this]);

            if (!$connection instanceof AggregateConnectionInterface) {
                throw new InvalidArgumentException(sprintf(
                    '%s expects the supplied callable to return an instance of %s, but %s was returned',
                    static::class,
                    AggregateConnectionInterface::class,
                    is_object($connection) ? get_class($connection) : gettype($connection)
                ));
            }

            if ($parameters && $autoaggregate) {
                static::aggregate($options, $connection, $parameters);
            }

            return $connection;
        };
    }

    /**
     * Adds single connections to an aggregate connection instance.
     *
     * @param OptionsInterface             $options    Client options
     * @param AggregateConnectionInterface $connection Target aggregate connection
     * @param array                        $nodes      List of nodes to be added to the target aggregate connection
     */
    public static function aggregate(OptionsInterface $options, AggregateConnectionInterface $connection, array $nodes)
    {
        $connections = $options->connections;

        foreach ($nodes as $node) {
            $connection->add($node instanceof NodeConnectionInterface ? $node : $connections->create($node));
        }
    }

    /**
     * {@inheritdoc}
     */
    public function getDefault(OptionsInterface $options)
    {
        return;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                predis/src/Configuration/Option/Connections.php                                                     0000644                 00000011715 15233650113 0015677 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Configuration\Option;

use InvalidArgumentException;
use Predis\Configuration\OptionInterface;
use Predis\Configuration\OptionsInterface;
use Predis\Connection\Factory;
use Predis\Connection\FactoryInterface;
use Predis\Connection\PhpiredisSocketConnection;
use Predis\Connection\PhpiredisStreamConnection;
use Predis\Connection\RelayConnection;

/**
 * Configures a new connection factory instance.
 *
 * The client uses the connection factory to create the underlying connections
 * to single redis nodes in a single-server configuration or in replication and
 * cluster configurations.
 */
class Connections implements OptionInterface
{
    /**
     * {@inheritdoc}
     */
    public function filter(OptionsInterface $options, $value)
    {
        if (is_callable($value)) {
            $value = call_user_func($value, $options);
        }

        if ($value instanceof FactoryInterface) {
            return $value;
        } elseif (is_array($value)) {
            return $this->createFactoryByArray($options, $value);
        } elseif (is_string($value)) {
            return $this->createFactoryByString($options, $value);
        } else {
            throw new InvalidArgumentException(sprintf(
                '%s expects a valid connection factory', static::class
            ));
        }
    }

    /**
     * Creates a new connection factory from a named array.
     *
     * The factory instance is configured according to the supplied named array
     * mapping URI schemes (passed as keys) to the FCQN of classes implementing
     * Predis\Connection\NodeConnectionInterface, or callable objects acting as
     * lazy initializers and returning new instances of classes implementing
     * Predis\Connection\NodeConnectionInterface.
     *
     * @param OptionsInterface $options Client options
     * @param array            $value   Named array mapping URI schemes to classes or callables
     *
     * @return FactoryInterface
     */
    protected function createFactoryByArray(OptionsInterface $options, array $value)
    {
        /**
         * @var FactoryInterface
         */
        $factory = $this->getDefault($options);

        foreach ($value as $scheme => $initializer) {
            $factory->define($scheme, $initializer);
        }

        return $factory;
    }

    /**
     * Creates a new connection factory from a descriptive string.
     *
     * The factory instance is configured according to the supplied descriptive
     * string that identifies specific configurations of schemes and connection
     * classes. Supported configuration values are:
     *
     * - "phpiredis-stream" maps tcp, redis, unix to PhpiredisStreamConnection
     * - "phpiredis-socket" maps tcp, redis, unix to PhpiredisSocketConnection
     * - "phpiredis" is an alias of "phpiredis-stream"
     * - "relay" maps tcp, redis, unix, tls, rediss to RelayConnection
     *
     * @param OptionsInterface $options Client options
     * @param string           $value   Descriptive string identifying the desired configuration
     *
     * @return FactoryInterface
     */
    protected function createFactoryByString(OptionsInterface $options, string $value)
    {
        /**
         * @var FactoryInterface
         */
        $factory = $this->getDefault($options);

        switch (strtolower($value)) {
            case 'phpiredis':
            case 'phpiredis-stream':
                $factory->define('tcp', PhpiredisStreamConnection::class);
                $factory->define('redis', PhpiredisStreamConnection::class);
                $factory->define('unix', PhpiredisStreamConnection::class);
                break;

            case 'phpiredis-socket':
                $factory->define('tcp', PhpiredisSocketConnection::class);
                $factory->define('redis', PhpiredisSocketConnection::class);
                $factory->define('unix', PhpiredisSocketConnection::class);
                break;

            case 'relay':
                $factory->define('tcp', RelayConnection::class);
                $factory->define('redis', RelayConnection::class);
                $factory->define('unix', RelayConnection::class);
                break;

            case 'default':
                return $factory;

            default:
                throw new InvalidArgumentException(sprintf(
                    '%s does not recognize `%s` as a supported configuration string', static::class, $value
                ));
        }

        return $factory;
    }

    /**
     * {@inheritdoc}
     */
    public function getDefault(OptionsInterface $options)
    {
        $factory = new Factory();

        if ($options->defined('parameters')) {
            $factory->setDefaultParameters($options->parameters);
        }

        return $factory;
    }
}
                                                   predis/src/Configuration/Option/CRC16.php                                                           0000644                 00000004102 15233650113 0014163 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Configuration\Option;

use InvalidArgumentException;
use Predis\Cluster\Hash;
use Predis\Configuration\OptionInterface;
use Predis\Configuration\OptionsInterface;

/**
 * Configures an hash generator used by the redis-cluster connection backend.
 */
class CRC16 implements OptionInterface
{
    /**
     * Returns an hash generator instance from a descriptive name.
     *
     * @param OptionsInterface $options     Client options.
     * @param string           $description Identifier of a hash generator (`predis`, `phpiredis`)
     *
     * @return callable
     */
    protected function getHashGeneratorByDescription(OptionsInterface $options, $description)
    {
        if ($description === 'predis') {
            return new Hash\CRC16();
        } elseif ($description === 'phpiredis') {
            return new Hash\PhpiredisCRC16();
        } else {
            throw new InvalidArgumentException(
                'String value for the crc16 option must be either `predis` or `phpiredis`'
            );
        }
    }

    /**
     * {@inheritdoc}
     */
    public function filter(OptionsInterface $options, $value)
    {
        if (is_callable($value)) {
            $value = call_user_func($value, $options);
        }

        if (is_string($value)) {
            return $this->getHashGeneratorByDescription($options, $value);
        } elseif ($value instanceof Hash\HashGeneratorInterface) {
            return $value;
        } else {
            $class = get_class($this);
            throw new InvalidArgumentException("$class expects a valid hash generator");
        }
    }

    /**
     * {@inheritdoc}
     */
    public function getDefault(OptionsInterface $options)
    {
        return function_exists('phpiredis_utils_crc16')
            ? new Hash\PhpiredisCRC16()
            : new Hash\CRC16();
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                              predis/src/Configuration/Option/Exceptions.php                                                      0000644                 00000001601 15233650113 0015527 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Configuration\Option;

use Predis\Configuration\OptionInterface;
use Predis\Configuration\OptionsInterface;

/**
 * Configures whether consumers (such as the client) should throw exceptions on
 * Redis errors (-ERR responses) or just return instances of error responses.
 */
class Exceptions implements OptionInterface
{
    /**
     * {@inheritdoc}
     */
    public function filter(OptionsInterface $options, $value)
    {
        return filter_var($value, FILTER_VALIDATE_BOOLEAN);
    }

    /**
     * {@inheritdoc}
     */
    public function getDefault(OptionsInterface $options)
    {
        return true;
    }
}
                                                                                                                               predis/src/Configuration/Option/Prefix.php                                                          0000644                 00000002170 15233650113 0014645 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Configuration\Option;

use Predis\Command\Processor\KeyPrefixProcessor;
use Predis\Command\Processor\ProcessorInterface;
use Predis\Configuration\OptionInterface;
use Predis\Configuration\OptionsInterface;

/**
 * Configures a command processor that apply the specified prefix string to a
 * series of Redis commands considered prefixable.
 */
class Prefix implements OptionInterface
{
    /**
     * {@inheritdoc}
     */
    public function filter(OptionsInterface $options, $value)
    {
        if (is_callable($value)) {
            $value = call_user_func($value, $options);
        }

        if ($value instanceof ProcessorInterface) {
            return $value;
        }

        return new KeyPrefixProcessor((string) $value);
    }

    /**
     * {@inheritdoc}
     */
    public function getDefault(OptionsInterface $options)
    {
        // NOOP
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                        predis/src/Configuration/Option/Cluster.php                                                         0000644                 00000005522 15233650113 0015035 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Configuration\Option;

use InvalidArgumentException;
use Predis\Cluster\RedisStrategy;
use Predis\Configuration\OptionsInterface;
use Predis\Connection\Cluster\PredisCluster;
use Predis\Connection\Cluster\RedisCluster;

/**
 * Configures an aggregate connection used for clustering
 * multiple Redis nodes using various implementations with
 * different algorithms or strategies.
 */
class Cluster extends Aggregate
{
    /**
     * {@inheritdoc}
     */
    public function filter(OptionsInterface $options, $value)
    {
        if (is_string($value)) {
            $value = $this->getConnectionInitializerByString($options, $value);
        }

        if (is_callable($value)) {
            return $this->getConnectionInitializer($options, $value);
        } else {
            throw new InvalidArgumentException(sprintf(
                '%s expects either a string or a callable value, %s given',
                static::class,
                is_object($value) ? get_class($value) : gettype($value)
            ));
        }
    }

    /**
     * Returns a connection initializer from a descriptive name.
     *
     * @param OptionsInterface $options     Client options
     * @param string           $description Identifier of a replication backend (`predis`, `sentinel`)
     *
     * @return callable
     */
    protected function getConnectionInitializerByString(OptionsInterface $options, string $description)
    {
        switch ($description) {
            case 'redis':
            case 'redis-cluster':
                return function ($parameters, $options, $option) {
                    return new RedisCluster($options->connections, new RedisStrategy($options->crc16));
                };

            case 'predis':
                return $this->getDefaultConnectionInitializer();

            default:
                throw new InvalidArgumentException(sprintf(
                    '%s expects either `predis`, `redis` or `redis-cluster` as valid string values, `%s` given',
                    static::class,
                    $description
                ));
        }
    }

    /**
     * Returns the default connection initializer.
     *
     * @return callable
     */
    protected function getDefaultConnectionInitializer()
    {
        return function ($parameters, $options, $option) {
            return new PredisCluster();
        };
    }

    /**
     * {@inheritdoc}
     */
    public function getDefault(OptionsInterface $options)
    {
        return $this->getConnectionInitializer(
            $options,
            $this->getDefaultConnectionInitializer()
        );
    }
}
                                                                                                                                                                              predis/src/Configuration/Option/Commands.php                                                        0000644                 00000010375 15233650113 0015157 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Configuration\Option;

use InvalidArgumentException;
use Predis\Command\FactoryInterface;
use Predis\Command\RawFactory;
use Predis\Command\RedisFactory;
use Predis\Configuration\OptionInterface;
use Predis\Configuration\OptionsInterface;

/**
 * Configures a connection factory to be used by the client.
 */
class Commands implements OptionInterface
{
    /**
     * {@inheritdoc}
     */
    public function filter(OptionsInterface $options, $value)
    {
        if (is_callable($value)) {
            $value = call_user_func($value, $options);
        }

        if ($value instanceof FactoryInterface) {
            return $value;
        } elseif (is_array($value)) {
            return $this->createFactoryByArray($options, $value);
        } elseif (is_string($value)) {
            return $this->createFactoryByString($options, $value);
        } else {
            throw new InvalidArgumentException(sprintf(
                '%s expects a valid command factory',
                static::class
            ));
        }
    }

    /**
     * Creates a new default command factory from a named array.
     *
     * The factory instance is configured according to the supplied named array
     * mapping command IDs (passed as keys) to the FCQN of classes implementing
     * Predis\Command\CommandInterface.
     *
     * @param OptionsInterface $options Client options container
     * @param array            $value   Named array mapping command IDs to classes
     *
     * @return FactoryInterface
     */
    protected function createFactoryByArray(OptionsInterface $options, array $value)
    {
        /**
         * @var FactoryInterface
         */
        $commands = $this->getDefault($options);

        foreach ($value as $commandID => $commandClass) {
            if ($commandClass === null) {
                $commands->undefine($commandID);
            } else {
                $commands->define($commandID, $commandClass);
            }
        }

        return $commands;
    }

    /**
     * Creates a new command factory from a descriptive string.
     *
     * The factory instance is configured according to the supplied descriptive
     * string that identifies specific configurations of schemes and connection
     * classes. Supported configuration values are:
     *
     * - "predis" returns the default command factory used by Predis
     * - "raw" returns a command factory that creates only raw commands
     * - "default" is simply an alias of "predis"
     *
     * @param OptionsInterface $options Client options container
     * @param string           $value   Descriptive string identifying the desired configuration
     *
     * @return FactoryInterface
     */
    protected function createFactoryByString(OptionsInterface $options, string $value)
    {
        switch (strtolower($value)) {
            case 'default':
            case 'predis':
                return $this->getDefault($options);

            case 'raw':
                return $this->createRawFactory($options);

            default:
                throw new InvalidArgumentException(sprintf(
                    '%s does not recognize `%s` as a supported configuration string',
                    static::class,
                    $value
                ));
        }
    }

    /**
     * Creates a new raw command factory instance.
     *
     * @param OptionsInterface $options Client options container
     */
    protected function createRawFactory(OptionsInterface $options): FactoryInterface
    {
        $commands = new RawFactory();

        if (isset($options->prefix)) {
            throw new InvalidArgumentException(sprintf(
                '%s does not support key prefixing', RawFactory::class
            ));
        }

        return $commands;
    }

    /**
     * {@inheritdoc}
     */
    public function getDefault(OptionsInterface $options)
    {
        $commands = new RedisFactory();

        if (isset($options->prefix)) {
            $commands->setProcessor($options->prefix);
        }

        return $commands;
    }
}
                                                                                                                                                                                                                                                                   predis/src/Configuration/OptionInterface.php                                                        0000644                 00000001663 15233650113 0015237 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Configuration;

/**
 * Defines an handler used by Predis\Configuration\Options to filter, validate
 * or return default values for a given option.
 */
interface OptionInterface
{
    /**
     * Filters and validates the passed value.
     *
     * @param OptionsInterface $options Options container.
     * @param mixed            $value   Input value.
     *
     * @return mixed
     */
    public function filter(OptionsInterface $options, $value);

    /**
     * Returns the default value for the option.
     *
     * @param OptionsInterface $options Options container.
     *
     * @return mixed
     */
    public function getDefault(OptionsInterface $options);
}
                                                                             predis/src/Response/Status.php                                                                      0000644                 00000003245 15233650113 0012416 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Response;

/**
 * Represents a status response returned by Redis.
 */
class Status implements ResponseInterface
{
    private static $OK;
    private static $QUEUED;

    private $payload;

    /**
     * @param string $payload Payload of the status response as returned by Redis.
     */
    public function __construct($payload)
    {
        $this->payload = $payload;
    }

    /**
     * Converts the response object to its string representation.
     *
     * @return string
     */
    public function __toString()
    {
        return $this->payload;
    }

    /**
     * Returns the payload of status response.
     *
     * @return string
     */
    public function getPayload()
    {
        return $this->payload;
    }

    /**
     * Returns an instance of a status response object.
     *
     * Common status responses such as OK or QUEUED are cached in order to lower
     * the global memory usage especially when using pipelines.
     *
     * @param string $payload Status response payload.
     *
     * @return self
     */
    public static function get($payload)
    {
        switch ($payload) {
            case 'OK':
            case 'QUEUED':
                if (isset(self::$$payload)) {
                    return self::$$payload;
                }

                return self::$$payload = new self($payload);

            default:
                return new self($payload);
        }
    }
}
                                                                                                                                                                                                                                                                                                                                                           predis/src/Response/Iterator/MultiBulkTuple.php                                                     0000644                 00000004413 15233650113 0015644 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Response\Iterator;

use InvalidArgumentException;
use OuterIterator;
use ReturnTypeWillChange;
use UnexpectedValueException;

/**
 * Outer iterator consuming streamable multibulk responses by yielding tuples of
 * keys and values.
 *
 * This wrapper is useful for responses to commands such as `HGETALL` that can
 * be iterator as $key => $value pairs.
 */
class MultiBulkTuple extends MultiBulk implements OuterIterator
{
    private $iterator;

    /**
     * @param MultiBulk $iterator Inner multibulk response iterator.
     */
    public function __construct(MultiBulk $iterator)
    {
        $this->checkPreconditions($iterator);

        $this->size = count($iterator) / 2;
        $this->iterator = $iterator;
        $this->position = $iterator->getPosition();
        $this->current = $this->size > 0 ? $this->getValue() : null;
    }

    /**
     * Checks for valid preconditions.
     *
     * @param MultiBulk $iterator Inner multibulk response iterator.
     *
     * @throws InvalidArgumentException
     * @throws UnexpectedValueException
     */
    protected function checkPreconditions(MultiBulk $iterator)
    {
        if ($iterator->getPosition() !== 0) {
            throw new InvalidArgumentException(
                'Cannot initialize a tuple iterator using an already initiated iterator.'
            );
        }

        if (($size = count($iterator)) % 2 !== 0) {
            throw new UnexpectedValueException('Invalid response size for a tuple iterator.');
        }
    }

    /**
     * @return MultiBulk
     */
    #[ReturnTypeWillChange]
    public function getInnerIterator()
    {
        return $this->iterator;
    }

    /**
     * {@inheritdoc}
     */
    public function __destruct()
    {
        $this->iterator->drop(true);
    }

    /**
     * {@inheritdoc}
     */
    protected function getValue()
    {
        $k = $this->iterator->current();
        $this->iterator->next();

        $v = $this->iterator->current();
        $this->iterator->next();

        return [$k, $v];
    }
}
                                                                                                                                                                                                                                                     predis/src/Response/Iterator/MultiBulk.php                                                          0000644                 00000003734 15233650113 0014637 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Response\Iterator;

use Predis\Connection\NodeConnectionInterface;

/**
 * Streamable multibulk response.
 */
class MultiBulk extends MultiBulkIterator
{
    private $connection;

    /**
     * @param NodeConnectionInterface $connection Connection to Redis.
     * @param int                     $size       Number of elements of the multibulk response.
     */
    public function __construct(NodeConnectionInterface $connection, $size)
    {
        $this->connection = $connection;
        $this->size = $size;
        $this->position = 0;
        $this->current = $size > 0 ? $this->getValue() : null;
    }

    /**
     * Handles the synchronization of the client with the Redis protocol when
     * the garbage collector kicks in (e.g. when the iterator goes out of the
     * scope of a foreach or it is unset).
     */
    public function __destruct()
    {
        $this->drop(true);
    }

    /**
     * Drop queued elements that have not been read from the connection either
     * by consuming the rest of the multibulk response or quickly by closing the
     * underlying connection.
     *
     * @param bool $disconnect Consume the iterator or drop the connection.
     */
    public function drop($disconnect = false)
    {
        if ($disconnect) {
            if ($this->valid()) {
                $this->position = $this->size;
                $this->connection->disconnect();
            }
        } else {
            while ($this->valid()) {
                $this->next();
            }
        }
    }

    /**
     * Reads the next item of the multibulk response from the connection.
     *
     * @return mixed
     */
    protected function getValue()
    {
        return $this->connection->read();
    }
}
                                    predis/src/Response/Iterator/MultiBulkIterator.php                                                  0000644                 00000004605 15233650113 0016347 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Response\Iterator;

use Countable;
use Iterator;
use Predis\Response\ResponseInterface;
use ReturnTypeWillChange;

/**
 * Iterator that abstracts the access to multibulk responses allowing them to be
 * consumed in a streamable fashion without keeping the whole payload in memory.
 *
 * This iterator does not support rewinding which means that the iteration, once
 * consumed, cannot be restarted.
 *
 * Always make sure that the whole iteration is consumed (or dropped) to prevent
 * protocol desynchronization issues.
 */
abstract class MultiBulkIterator implements Iterator, Countable, ResponseInterface
{
    protected $current;
    protected $position;
    protected $size;

    /**
     * @return void
     */
    #[ReturnTypeWillChange]
    public function rewind()
    {
        // NOOP
    }

    /**
     * @return mixed
     */
    #[ReturnTypeWillChange]
    public function current()
    {
        return $this->current;
    }

    /**
     * @return int|null
     */
    #[ReturnTypeWillChange]
    public function key()
    {
        return $this->position;
    }

    /**
     * @return void
     */
    #[ReturnTypeWillChange]
    public function next()
    {
        if (++$this->position < $this->size) {
            $this->current = $this->getValue();
        }
    }

    /**
     * @return bool
     */
    #[ReturnTypeWillChange]
    public function valid()
    {
        return $this->position < $this->size;
    }

    /**
     * Returns the number of items comprising the whole multibulk response.
     *
     * This method should be used instead of iterator_count() to get the size of
     * the current multibulk response since the former consumes the iteration to
     * count the number of elements, but our iterators do not support rewinding.
     *
     * @return int
     */
    #[ReturnTypeWillChange]
    public function count()
    {
        return $this->size;
    }

    /**
     * Returns the current position of the iterator.
     *
     * @return int
     */
    public function getPosition()
    {
        return $this->position;
    }

    /**
     * {@inheritdoc}
     */
    abstract protected function getValue();
}
                                                                                                                           predis/src/Response/ErrorInterface.php                                                              0000644                 00000001351 15233650113 0014041 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Response;

/**
 * Represents an error returned by Redis (responses identified by "-" in the
 * Redis protocol) during the execution of an operation on the server.
 */
interface ErrorInterface extends ResponseInterface
{
    /**
     * Returns the error message.
     *
     * @return string
     */
    public function getMessage();

    /**
     * Returns the error type (e.g. ERR, ASK, MOVED).
     *
     * @return string
     */
    public function getErrorType();
}
                                                                                                                                                                                                                                                                                       predis/src/Response/ServerException.php                                                             0000644                 00000001612 15233650113 0014254 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Response;

use Predis\PredisException;

/**
 * Exception class that identifies server-side Redis errors.
 */
class ServerException extends PredisException implements ErrorInterface
{
    /**
     * Gets the type of the error returned by Redis.
     *
     * @return string
     */
    public function getErrorType()
    {
        [$errorType] = explode(' ', $this->getMessage(), 2);

        return $errorType;
    }

    /**
     * Converts the exception to an instance of Predis\Response\Error.
     *
     * @return Error
     */
    public function toErrorResponse()
    {
        return new Error($this->getMessage());
    }
}
                                                                                                                      predis/src/Response/ResponseInterface.php                                                           0000644                 00000000571 15233650113 0014551 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Response;

/**
 * Represents a complex response object from Redis.
 */
interface ResponseInterface
{
}
                                                                                                                                       predis/src/Response/Error.php                                                                       0000644                 00000002123 15233650113 0012216 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Response;

/**
 * Represents an error returned by Redis (-ERR responses) during the execution
 * of a command on the server.
 */
class Error implements ErrorInterface
{
    private $message;

    /**
     * @param string $message Error message returned by Redis
     */
    public function __construct($message)
    {
        $this->message = $message;
    }

    /**
     * {@inheritdoc}
     */
    public function getMessage()
    {
        return $this->message;
    }

    /**
     * {@inheritdoc}
     */
    public function getErrorType()
    {
        [$errorType] = explode(' ', $this->getMessage(), 2);

        return $errorType;
    }

    /**
     * Converts the object to its string representation.
     *
     * @return string
     */
    public function __toString()
    {
        return $this->getMessage();
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                             predis/src/NotSupportedException.php                                                                0000644                 00000000711 15233650113 0013655 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis;

/**
 * Exception class thrown when trying to use features not supported by certain
 * classes or abstractions of Predis.
 */
class NotSupportedException extends PredisException
{
}
                                                       predis/src/PredisException.php                                                                      0000644                 00000000624 15233650113 0012440 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis;

use Exception;

/**
 * Base exception class for Predis-related errors.
 */
abstract class PredisException extends Exception
{
}
                                                                                                            predis/src/Protocol/ProtocolException.php                                                           0000644                 00000000737 15233650113 0014621 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Protocol;

use Predis\CommunicationException;

/**
 * Exception used to identify errors encountered while parsing the Redis wire
 * protocol.
 */
class ProtocolException extends CommunicationException
{
}
                                 predis/src/Protocol/ResponseReaderInterface.php                                                     0000644                 00000001353 15233650113 0015676 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Protocol;

use Predis\Connection\CompositeConnectionInterface;

/**
 * Defines a pluggable reader capable of parsing responses returned by Redis and
 * deserializing them to PHP objects.
 */
interface ResponseReaderInterface
{
    /**
     * Reads a response from a connection to Redis.
     *
     * @param CompositeConnectionInterface $connection Redis connection.
     *
     * @return mixed
     */
    public function read(CompositeConnectionInterface $connection);
}
                                                                                                                                                                                                                                                                                     predis/src/Protocol/RequestSerializerInterface.php                                                  0000644                 00000001162 15233650113 0016435 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Protocol;

use Predis\Command\CommandInterface;

/**
 * Defines a pluggable serializer for Redis commands.
 */
interface RequestSerializerInterface
{
    /**
     * Serializes a Redis command.
     *
     * @param CommandInterface $command Redis command.
     *
     * @return string
     */
    public function serialize(CommandInterface $command);
}
                                                                                                                                                                                                                                                                                                                                                                                                              predis/src/Protocol/Text/ResponseReader.php                                                         0000644                 00000006013 15233650113 0014777 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Protocol\Text;

use Predis\CommunicationException;
use Predis\Connection\CompositeConnectionInterface;
use Predis\Protocol\ProtocolException;
use Predis\Protocol\ResponseReaderInterface;

/**
 * Response reader for the standard Redis wire protocol.
 *
 * @see http://redis.io/topics/protocol
 */
class ResponseReader implements ResponseReaderInterface
{
    protected $handlers;

    public function __construct()
    {
        $this->handlers = $this->getDefaultHandlers();
    }

    /**
     * Returns the default handlers for the supported type of responses.
     *
     * @return array
     */
    protected function getDefaultHandlers()
    {
        return [
            '+' => new Handler\StatusResponse(),
            '-' => new Handler\ErrorResponse(),
            ':' => new Handler\IntegerResponse(),
            '$' => new Handler\BulkResponse(),
            '*' => new Handler\MultiBulkResponse(),
        ];
    }

    /**
     * Sets the handler for the specified prefix identifying the response type.
     *
     * @param string                           $prefix  Identifier of the type of response.
     * @param Handler\ResponseHandlerInterface $handler Response handler.
     */
    public function setHandler($prefix, Handler\ResponseHandlerInterface $handler)
    {
        $this->handlers[$prefix] = $handler;
    }

    /**
     * Returns the response handler associated to a certain type of response.
     *
     * @param string $prefix Identifier of the type of response.
     *
     * @return Handler\ResponseHandlerInterface
     */
    public function getHandler($prefix)
    {
        if (isset($this->handlers[$prefix])) {
            return $this->handlers[$prefix];
        }

        return;
    }

    /**
     * {@inheritdoc}
     */
    public function read(CompositeConnectionInterface $connection)
    {
        $header = $connection->readLine();

        if ($header === '') {
            $this->onProtocolError($connection, 'Unexpected empty response header');
        }

        $prefix = $header[0];

        if (!isset($this->handlers[$prefix])) {
            $this->onProtocolError($connection, "Unknown response prefix: '$prefix'");
        }

        return $this->handlers[$prefix]->handle($connection, substr($header, 1));
    }

    /**
     * Handles protocol errors generated while reading responses from a
     * connection.
     *
     * @param CompositeConnectionInterface $connection Redis connection that generated the error.
     * @param string                       $message    Error message.
     */
    protected function onProtocolError(CompositeConnectionInterface $connection, $message)
    {
        CommunicationException::handle(
            new ProtocolException($connection, "$message [{$connection->getParameters()}]")
        );
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     predis/src/Protocol/Text/ProtocolProcessor.php                                                      0000644                 00000006400 15233650113 0015557 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Protocol\Text;

use Predis\Command\CommandInterface;
use Predis\CommunicationException;
use Predis\Connection\CompositeConnectionInterface;
use Predis\Protocol\ProtocolException;
use Predis\Protocol\ProtocolProcessorInterface;
use Predis\Response\Error as ErrorResponse;
use Predis\Response\Iterator\MultiBulk as MultiBulkIterator;
use Predis\Response\Status as StatusResponse;

/**
 * Protocol processor for the standard Redis wire protocol.
 *
 * @see http://redis.io/topics/protocol
 */
class ProtocolProcessor implements ProtocolProcessorInterface
{
    protected $mbiterable;
    protected $serializer;

    public function __construct()
    {
        $this->mbiterable = false;
        $this->serializer = new RequestSerializer();
    }

    /**
     * {@inheritdoc}
     */
    public function write(CompositeConnectionInterface $connection, CommandInterface $command)
    {
        $request = $this->serializer->serialize($command);
        $connection->writeBuffer($request);
    }

    /**
     * {@inheritdoc}
     */
    public function read(CompositeConnectionInterface $connection)
    {
        $chunk = $connection->readLine();
        $prefix = $chunk[0];
        $payload = substr($chunk, 1);

        switch ($prefix) {
            case '+':
                return new StatusResponse($payload);

            case '$':
                $size = (int) $payload;
                if ($size === -1) {
                    return;
                }

                return substr($connection->readBuffer($size + 2), 0, -2);

            case '*':
                $count = (int) $payload;

                if ($count === -1) {
                    return;
                }
                if ($this->mbiterable) {
                    return new MultiBulkIterator($connection, $count);
                }

                $multibulk = [];

                for ($i = 0; $i < $count; ++$i) {
                    $multibulk[$i] = $this->read($connection);
                }

                return $multibulk;

            case ':':
                $integer = (int) $payload;

                return $integer == $payload ? $integer : $payload;

            case '-':
                return new ErrorResponse($payload);

            default:
                CommunicationException::handle(new ProtocolException(
                    $connection, "Unknown response prefix: '$prefix' [{$connection->getParameters()}]"
                ));

                return;
        }
    }

    /**
     * Enables or disables returning multibulk responses as specialized PHP
     * iterators used to stream bulk elements of a multibulk response instead
     * returning a plain array.
     *
     * Streamable multibulk responses are not globally supported by the
     * abstractions built-in into Predis, such as transactions or pipelines.
     * Use them with care!
     *
     * @param bool $value Enable or disable streamable multibulk responses.
     */
    public function useIterableMultibulk($value)
    {
        $this->mbiterable = (bool) $value;
    }
}
                                                                                                                                                                                                                                                                predis/src/Protocol/Text/RequestSerializer.php                                                      0000644                 00000002060 15233650113 0015536 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Protocol\Text;

use Predis\Command\CommandInterface;
use Predis\Protocol\RequestSerializerInterface;

/**
 * Request serializer for the standard Redis wire protocol.
 *
 * @see http://redis.io/topics/protocol
 */
class RequestSerializer implements RequestSerializerInterface
{
    /**
     * {@inheritdoc}
     */
    public function serialize(CommandInterface $command)
    {
        $commandID = $command->getId();
        $arguments = $command->getArguments();

        $cmdlen = strlen($commandID);
        $reqlen = count($arguments) + 1;

        $buffer = "*{$reqlen}\r\n\${$cmdlen}\r\n{$commandID}\r\n";

        foreach ($arguments as $argument) {
            $arglen = strlen($argument);
            $buffer .= "\${$arglen}\r\n{$argument}\r\n";
        }

        return $buffer;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                predis/src/Protocol/Text/Handler/IntegerResponse.php                                                0000644                 00000002262 15233650113 0016551 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Protocol\Text\Handler;

use Predis\CommunicationException;
use Predis\Connection\CompositeConnectionInterface;
use Predis\Protocol\ProtocolException;

/**
 * Handler for the integer response type in the standard Redis wire protocol.
 * It translates the payload an integer or NULL.
 *
 * @see http://redis.io/topics/protocol
 */
class IntegerResponse implements ResponseHandlerInterface
{
    /**
     * {@inheritdoc}
     */
    public function handle(CompositeConnectionInterface $connection, $payload)
    {
        if (is_numeric($payload)) {
            $integer = (int) $payload;

            return $integer == $payload ? $integer : $payload;
        }

        if ($payload !== 'nil') {
            CommunicationException::handle(new ProtocolException(
                $connection, "Cannot parse '$payload' as a valid numeric response [{$connection->getParameters()}]"
            ));
        }

        return;
    }
}
                                                                                                                                                                                                                                                                                                                                              predis/src/Protocol/Text/Handler/MultiBulkResponse.php                                              0000644                 00000003462 15233650113 0017067 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Protocol\Text\Handler;

use Predis\CommunicationException;
use Predis\Connection\CompositeConnectionInterface;
use Predis\Protocol\ProtocolException;

/**
 * Handler for the multibulk response type in the standard Redis wire protocol.
 * It returns multibulk responses as PHP arrays.
 *
 * @see http://redis.io/topics/protocol
 */
class MultiBulkResponse implements ResponseHandlerInterface
{
    /**
     * {@inheritdoc}
     */
    public function handle(CompositeConnectionInterface $connection, $payload)
    {
        $length = (int) $payload;

        if ("$length" !== $payload) {
            CommunicationException::handle(new ProtocolException(
                $connection, "Cannot parse '$payload' as a valid length of a multi-bulk response [{$connection->getParameters()}]"
            ));
        }

        if ($length === -1) {
            return;
        }

        $list = [];

        if ($length > 0) {
            $handlersCache = [];
            $reader = $connection->getProtocol()->getResponseReader();

            for ($i = 0; $i < $length; ++$i) {
                $header = $connection->readLine();
                $prefix = $header[0];

                if (isset($handlersCache[$prefix])) {
                    $handler = $handlersCache[$prefix];
                } else {
                    $handler = $reader->getHandler($prefix);
                    $handlersCache[$prefix] = $handler;
                }

                $list[$i] = $handler->handle($connection, substr($header, 1));
            }
        }

        return $list;
    }
}
                                                                                                                                                                                                              predis/src/Protocol/Text/Handler/ErrorResponse.php                                                  0000644                 00000001437 15233650113 0016250 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Protocol\Text\Handler;

use Predis\Connection\CompositeConnectionInterface;
use Predis\Response\Error;

/**
 * Handler for the error response type in the standard Redis wire protocol.
 * It translates the payload to a complex response object for Predis.
 *
 * @see http://redis.io/topics/protocol
 */
class ErrorResponse implements ResponseHandlerInterface
{
    /**
     * {@inheritdoc}
     */
    public function handle(CompositeConnectionInterface $connection, $payload)
    {
        return new Error($payload);
    }
}
                                                                                                                                                                                                                                 predis/src/Protocol/Text/Handler/StreamableMultiBulkResponse.php                                    0000644                 00000002612 15233650113 0021063 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Protocol\Text\Handler;

use Predis\CommunicationException;
use Predis\Connection\CompositeConnectionInterface;
use Predis\Protocol\ProtocolException;
use Predis\Response\Iterator\MultiBulk as MultiBulkIterator;

/**
 * Handler for the multibulk response type in the standard Redis wire protocol.
 * It returns multibulk responses as iterators that can stream bulk elements.
 *
 * Streamable multibulk responses are not globally supported by the abstractions
 * built-in into Predis, such as transactions or pipelines. Use them with care!
 *
 * @see http://redis.io/topics/protocol
 */
class StreamableMultiBulkResponse implements ResponseHandlerInterface
{
    /**
     * {@inheritdoc}
     */
    public function handle(CompositeConnectionInterface $connection, $payload)
    {
        $length = (int) $payload;

        if ("$length" != $payload) {
            CommunicationException::handle(new ProtocolException(
                $connection, "Cannot parse '$payload' as a valid length for a multi-bulk response [{$connection->getParameters()}]"
            ));
        }

        return new MultiBulkIterator($connection, $length);
    }
}
                                                                                                                      predis/src/Protocol/Text/Handler/StatusResponse.php                                                 0000644                 00000001515 15233650113 0016437 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Protocol\Text\Handler;

use Predis\Connection\CompositeConnectionInterface;
use Predis\Response\Status;

/**
 * Handler for the status response type in the standard Redis wire protocol. It
 * translates certain classes of status response to PHP objects or just returns
 * the payload as a string.
 *
 * @see http://redis.io/topics/protocol
 */
class StatusResponse implements ResponseHandlerInterface
{
    /**
     * {@inheritdoc}
     */
    public function handle(CompositeConnectionInterface $connection, $payload)
    {
        return Status::get($payload);
    }
}
                                                                                                                                                                                   predis/src/Protocol/Text/Handler/BulkResponse.php                                                   0000644                 00000002667 15233650113 0016062 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Protocol\Text\Handler;

use Predis\CommunicationException;
use Predis\Connection\CompositeConnectionInterface;
use Predis\Protocol\ProtocolException;

/**
 * Handler for the bulk response type in the standard Redis wire protocol.
 * It translates the payload to a string or a NULL.
 *
 * @see http://redis.io/topics/protocol
 */
class BulkResponse implements ResponseHandlerInterface
{
    /**
     * {@inheritdoc}
     */
    public function handle(CompositeConnectionInterface $connection, $payload)
    {
        $length = (int) $payload;

        if ("$length" !== $payload) {
            CommunicationException::handle(new ProtocolException(
                $connection, "Cannot parse '$payload' as a valid length for a bulk response [{$connection->getParameters()}]"
            ));
        }

        if ($length >= 0) {
            return substr($connection->readBuffer($length + 2), 0, -2);
        }

        if ($length == -1) {
            return;
        }

        CommunicationException::handle(new ProtocolException(
            $connection, "Value '$payload' is not a valid length for a bulk response [{$connection->getParameters()}]"
        ));

        return;
    }
}
                                                                         predis/src/Protocol/Text/Handler/ResponseHandlerInterface.php                                       0000644                 00000001530 15233650113 0020347 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Protocol\Text\Handler;

use Predis\Connection\CompositeConnectionInterface;

/**
 * Defines a pluggable handler used to parse a particular type of response.
 */
interface ResponseHandlerInterface
{
    /**
     * Deserializes a response returned by Redis and reads more data from the
     * connection if needed.
     *
     * @param CompositeConnectionInterface $connection Redis connection.
     * @param string                       $payload    String payload.
     *
     * @return mixed
     */
    public function handle(CompositeConnectionInterface $connection, $payload);
}
                                                                                                                                                                        predis/src/Protocol/Text/CompositeProtocolProcessor.php                                             0000644                 00000005345 15233650113 0017451 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Protocol\Text;

use Predis\Command\CommandInterface;
use Predis\Connection\CompositeConnectionInterface;
use Predis\Protocol\ProtocolProcessorInterface;
use Predis\Protocol\RequestSerializerInterface;
use Predis\Protocol\ResponseReaderInterface;

/**
 * Composite protocol processor for the standard Redis wire protocol using
 * pluggable handlers to serialize requests and deserialize responses.
 *
 * @see http://redis.io/topics/protocol
 */
class CompositeProtocolProcessor implements ProtocolProcessorInterface
{
    /*
     * @var RequestSerializerInterface
     */
    protected $serializer;

    /*
     * @var ResponseReaderInterface
     */
    protected $reader;

    /**
     * @param RequestSerializerInterface $serializer Request serializer.
     * @param ResponseReaderInterface    $reader     Response reader.
     */
    public function __construct(
        RequestSerializerInterface $serializer = null,
        ResponseReaderInterface $reader = null
    ) {
        $this->setRequestSerializer($serializer ?: new RequestSerializer());
        $this->setResponseReader($reader ?: new ResponseReader());
    }

    /**
     * {@inheritdoc}
     */
    public function write(CompositeConnectionInterface $connection, CommandInterface $command)
    {
        $connection->writeBuffer($this->serializer->serialize($command));
    }

    /**
     * {@inheritdoc}
     */
    public function read(CompositeConnectionInterface $connection)
    {
        return $this->reader->read($connection);
    }

    /**
     * Sets the request serializer used by the protocol processor.
     *
     * @param RequestSerializerInterface $serializer Request serializer.
     */
    public function setRequestSerializer(RequestSerializerInterface $serializer)
    {
        $this->serializer = $serializer;
    }

    /**
     * Returns the request serializer used by the protocol processor.
     *
     * @return RequestSerializerInterface
     */
    public function getRequestSerializer()
    {
        return $this->serializer;
    }

    /**
     * Sets the response reader used by the protocol processor.
     *
     * @param ResponseReaderInterface $reader Response reader.
     */
    public function setResponseReader(ResponseReaderInterface $reader)
    {
        $this->reader = $reader;
    }

    /**
     * Returns the Response reader used by the protocol processor.
     *
     * @return ResponseReaderInterface
     */
    public function getResponseReader()
    {
        return $this->reader;
    }
}
                                                                                                                                                                                                                                                                                           predis/src/Protocol/ProtocolProcessorInterface.php                                                  0000644                 00000002160 15233650113 0016453 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Protocol;

use Predis\Command\CommandInterface;
use Predis\Connection\CompositeConnectionInterface;

/**
 * Defines a pluggable protocol processor capable of serializing commands and
 * deserializing responses into PHP objects directly from a connection.
 */
interface ProtocolProcessorInterface
{
    /**
     * Writes a request over a connection to Redis.
     *
     * @param CompositeConnectionInterface $connection Redis connection.
     * @param CommandInterface             $command    Command instance.
     */
    public function write(CompositeConnectionInterface $connection, CommandInterface $command);

    /**
     * Reads a response from a connection to Redis.
     *
     * @param CompositeConnectionInterface $connection Redis connection.
     *
     * @return mixed
     */
    public function read(CompositeConnectionInterface $connection);
}
                                                                                                                                                                                                                                                                                                                                                                                                                predis/src/Monitor/Consumer.php                                                                     0000644                 00000010217 15233650113 0012554 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Monitor;

use Iterator;
use Predis\ClientInterface;
use Predis\Connection\Cluster\ClusterInterface;
use Predis\NotSupportedException;
use ReturnTypeWillChange;

/**
 * Redis MONITOR consumer.
 */
class Consumer implements Iterator
{
    private $client;
    private $valid;
    private $position;

    /**
     * @param ClientInterface $client Client instance used by the consumer.
     */
    public function __construct(ClientInterface $client)
    {
        $this->assertClient($client);

        $this->client = $client;

        $this->start();
    }

    /**
     * Automatically stops the consumer when the garbage collector kicks in.
     */
    public function __destruct()
    {
        $this->stop();
    }

    /**
     * Checks if the passed client instance satisfies the required conditions
     * needed to initialize a monitor consumer.
     *
     * @param ClientInterface $client Client instance used by the consumer.
     *
     * @throws NotSupportedException
     */
    private function assertClient(ClientInterface $client)
    {
        if ($client->getConnection() instanceof ClusterInterface) {
            throw new NotSupportedException(
                'Cannot initialize a monitor consumer over cluster connections.'
            );
        }

        if (!$client->getCommandFactory()->supports('MONITOR')) {
            throw new NotSupportedException("'MONITOR' is not supported by the current command factory.");
        }
    }

    /**
     * Initializes the consumer and sends the MONITOR command to the server.
     */
    protected function start()
    {
        $this->client->executeCommand(
            $this->client->createCommand('MONITOR')
        );
        $this->valid = true;
    }

    /**
     * Stops the consumer. Internally this is done by disconnecting from server
     * since there is no way to terminate the stream initialized by MONITOR.
     */
    public function stop()
    {
        $this->client->disconnect();
        $this->valid = false;
    }

    /**
     * @return void
     */
    #[ReturnTypeWillChange]
    public function rewind()
    {
        // NOOP
    }

    /**
     * Returns the last message payload retrieved from the server.
     *
     * @return object
     */
    #[ReturnTypeWillChange]
    public function current()
    {
        return $this->getValue();
    }

    /**
     * @return int|null
     */
    #[ReturnTypeWillChange]
    public function key()
    {
        return $this->position;
    }

    /**
     * @return void
     */
    #[ReturnTypeWillChange]
    public function next()
    {
        ++$this->position;
    }

    /**
     * Checks if the the consumer is still in a valid state to continue.
     *
     * @return bool
     */
    #[ReturnTypeWillChange]
    public function valid()
    {
        return $this->valid;
    }

    /**
     * Waits for a new message from the server generated by MONITOR and returns
     * it when available.
     *
     * @return object
     */
    private function getValue()
    {
        $database = 0;
        $client = null;
        $event = $this->client->getConnection()->read();

        $callback = function ($matches) use (&$database, &$client) {
            if (2 === $count = count($matches)) {
                // Redis <= 2.4
                $database = (int) $matches[1];
            }

            if (4 === $count) {
                // Redis >= 2.6
                $database = (int) $matches[2];
                $client = $matches[3];
            }

            return ' ';
        };

        $event = preg_replace_callback('/ \(db (\d+)\) | \[(\d+) (.*?)\] /', $callback, $event, 1);
        @[$timestamp, $command, $arguments] = explode(' ', $event, 3);

        return (object) [
            'timestamp' => (float) $timestamp,
            'database' => $database,
            'client' => $client,
            'command' => substr($command, 1, -1),
            'arguments' => $arguments,
        ];
    }
}
                                                                                                                                                                                                                                                                                                                                                                                 predis/src/ClientInterface.php                                                                      0000644                 00000065547 15233650113 0012411 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis;

use Predis\Command\Argument\Geospatial\ByInterface;
use Predis\Command\Argument\Geospatial\FromInterface;
use Predis\Command\Argument\Search\AggregateArguments;
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\ProfileArguments;
use Predis\Command\Argument\Search\SchemaFields\FieldInterface;
use Predis\Command\Argument\Search\SearchArguments;
use Predis\Command\Argument\Search\SugAddArguments;
use Predis\Command\Argument\Search\SugGetArguments;
use Predis\Command\Argument\Search\SynUpdateArguments;
use Predis\Command\Argument\Server\LimitOffsetCount;
use Predis\Command\Argument\Server\To;
use Predis\Command\Argument\TimeSeries\AddArguments;
use Predis\Command\Argument\TimeSeries\AlterArguments as TSAlterArguments;
use Predis\Command\Argument\TimeSeries\CreateArguments as TSCreateArguments;
use Predis\Command\Argument\TimeSeries\DecrByArguments;
use Predis\Command\Argument\TimeSeries\GetArguments;
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\RangeArguments;
use Predis\Command\CommandInterface;
use Predis\Command\FactoryInterface;
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\Response\Status;

/**
 * Interface defining a client able to execute commands against Redis.
 *
 * All the commands exposed by the client generally have the same signature as
 * described by the Redis documentation, but some of them offer an additional
 * and more friendly interface to ease programming which is described in the
 * following list of methods:
 *
 * @method int               copy(string $source, string $destination, int $db = -1, bool $replace = false)
 * @method int               del(string[]|string $keyOrKeys, string ...$keys = null)
 * @method string|null       dump(string $key)
 * @method int               exists(string $key)
 * @method int               expire(string $key, int $seconds, string $expireOption = '')
 * @method int               expireat(string $key, int $timestamp, string $expireOption = '')
 * @method int               expiretime(string $key)
 * @method array             keys(string $pattern)
 * @method int               move(string $key, int $db)
 * @method mixed             object($subcommand, string $key)
 * @method int               persist(string $key)
 * @method int               pexpire(string $key, int $milliseconds)
 * @method int               pexpireat(string $key, int $timestamp)
 * @method int               pttl(string $key)
 * @method string|null       randomkey()
 * @method mixed             rename(string $key, string $target)
 * @method int               renamenx(string $key, string $target)
 * @method array             scan($cursor, array $options = null)
 * @method array             sort(string $key, array $options = null)
 * @method 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               append(string $key, $value)
 * @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)
 * @method array             bfmadd(string $key, ...$item)
 * @method array             bfmexists(string $key, ...$item)
 * @method Status            bfreserve(string $key, float $errorRate, int $capacity, int $expansion = -1, bool $nonScaling = false)
 * @method array             bfscandump(string $key, int $iterator)
 * @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 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 int               cfadd(string $key, $item)
 * @method int               cfaddnx(string $key, $item)
 * @method int               cfcount(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)
 * @method array             cfinsert(string $key, int $capacity = -1, bool $noCreate = false, string ...$item)
 * @method array             cfinsertnx(string $key, int $capacity = -1, bool $noCreate = false, string ...$item)
 * @method Status            cfreserve(string $key, int $capacity, int $bucketSize = -1, int $maxIterations = -1, int $expansion = -1)
 * @method array             cfscandump(string $key, int $iterator)
 * @method array             cmsincrby(string $key, string|int...$itemIncrementDictionary)
 * @method array             cmsinfo(string $key)
 * @method Status            cmsinitbydim(string $key, int $width, int $depth)
 * @method Status            cmsinitbyprob(string $key, float $errorRate, float $probability)
 * @method Status            cmsmerge(string $destination, array $sources, array $weights = [])
 * @method array             cmsquery(string $key, string ...$item)
 * @method int               decr(string $key)
 * @method int               decrby(string $key, int $decrement)
 * @method Status            failover(?To $to = null, bool $abort = false, int $timeout = -1)
 * @method mixed             fcall(string $function, array $keys, ...$args)
 * @method mixed             fcall_ro(string $function, array $keys, ...$args)
 * @method array             ftaggregate(string $index, string $query, ?AggregateArguments $arguments = null)
 * @method Status            ftaliasadd(string $alias, string $index)
 * @method Status            ftaliasdel(string $alias)
 * @method Status            ftaliasupdate(string $alias, string $index)
 * @method Status            ftalter(string $index, FieldInterface[] $schema, ?AlterArguments $arguments = null)
 * @method Status            ftcreate(string $index, FieldInterface[] $schema, ?CreateArguments $arguments = null)
 * @method int               ftdictadd(string $dict, ...$term)
 * @method int               ftdictdel(string $dict, ...$term)
 * @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             ftinfo(string $index)
 * @method array             ftprofile(string $index, ProfileArguments $arguments)
 * @method array             ftsearch(string $index, string $query, ?SearchArguments $arguments = null)
 * @method array             ftspellcheck(string $index, string $query, ?SearchArguments $arguments = null)
 * @method int               ftsugadd(string $key, string $string, float $score, ?SugAddArguments $arguments = null)
 * @method int               ftsugdel(string $key, string $string)
 * @method array             ftsugget(string $key, string $prefix, ?SugGetArguments $arguments = null)
 * @method int               ftsuglen(string $key)
 * @method array             ftsyndump(string $index)
 * @method Status            ftsynupdate(string $index, string $synonymGroupId, ?SynUpdateArguments $arguments = null, string ...$terms)
 * @method array             fttagvals(string $index, string $fieldName)
 * @method string|null       get(string $key)
 * @method int               getbit(string $key, $offset)
 * @method int|null          getex(string $key, $modifier = '', $value = false)
 * @method string            getrange(string $key, $start, $end)
 * @method string            getdel(string $key)
 * @method string|null       getset(string $key, $value)
 * @method int               incr(string $key)
 * @method int               incrby(string $key, int $increment)
 * @method string            incrbyfloat(string $key, int|float $increment)
 * @method array             mget(string[]|string $keyOrKeys, string ...$keys = null)
 * @method mixed             mset(array $dictionary)
 * @method int               msetnx(array $dictionary)
 * @method Status            psetex(string $key, $milliseconds, $value)
 * @method Status            set(string $key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
 * @method int               setbit(string $key, $offset, $value)
 * @method Status            setex(string $key, $seconds, $value)
 * @method int               setnx(string $key, $value)
 * @method int               setrange(string $key, $offset, $value)
 * @method int               strlen(string $key)
 * @method int               hdel(string $key, array $fields)
 * @method int               hexists(string $key, string $field)
 * @method string|null       hget(string $key, string $field)
 * @method array             hgetall(string $key)
 * @method int               hincrby(string $key, string $field, int $increment)
 * @method string            hincrbyfloat(string $key, string $field, int|float $increment)
 * @method array             hkeys(string $key)
 * @method int               hlen(string $key)
 * @method array             hmget(string $key, array $fields)
 * @method mixed             hmset(string $key, array $dictionary)
 * @method array             hrandfield(string $key, int $count = 1, bool $withValues = false)
 * @method array             hscan(string $key, $cursor, array $options = null)
 * @method int               hset(string $key, string $field, string $value)
 * @method int               hsetnx(string $key, string $field, string $value)
 * @method array             hvals(string $key)
 * @method int               hstrlen(string $key, string $field)
 * @method array             jsonarrappend(string $key, string $path = '$', ...$value)
 * @method array             jsonarrindex(string $key, string $path, string $value, int $start = 0, int $stop = 0)
 * @method array             jsonarrinsert(string $key, string $path, int $index, string ...$value)
 * @method array             jsonarrlen(string $key, string $path = '$')
 * @method array             jsonarrpop(string $key, string $path = '$', int $index = -1)
 * @method int               jsonclear(string $key, string $path = '$')
 * @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 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)
 * @method array             jsonstrappend(string $key, string $path, string $value)
 * @method array             jsonstrlen(string $key, string $path = '$')
 * @method array             jsontoggle(string $key, string $path)
 * @method array             jsontype(string $key, string $path = '$')
 * @method string            blmove(string $source, string $destination, string $where, string $to, int $timeout)
 * @method array|null        blpop(array|string $keys, int|float $timeout)
 * @method array|null        brpop(array|string $keys, int|float $timeout)
 * @method string|null       brpoplpush(string $source, string $destination, int|float $timeout)
 * @method mixed             lcs(string $key1, string $key2, bool $len = false, bool $idx = false, int $minMatchLen = 0, bool $withMatchLen = false)
 * @method string|null       lindex(string $key, int $index)
 * @method int               linsert(string $key, $whence, $pivot, $value)
 * @method int               llen(string $key)
 * @method string            lmove(string $source, string $destination, string $where, string $to)
 * @method array|null        lmpop(array $keys, string $modifier = 'left', int $count = 1)
 * @method string|null       lpop(string $key)
 * @method int               lpush(string $key, array $values)
 * @method int               lpushx(string $key, array $values)
 * @method string[]          lrange(string $key, int $start, int $stop)
 * @method int               lrem(string $key, int $count, string $value)
 * @method mixed             lset(string $key, int $index, string $value)
 * @method mixed             ltrim(string $key, int $start, int $stop)
 * @method string|null       rpop(string $key)
 * @method string|null       rpoplpush(string $source, string $destination)
 * @method int               rpush(string $key, array $values)
 * @method int               rpushx(string $key, array $values)
 * @method int               sadd(string $key, array $members)
 * @method int               scard(string $key)
 * @method string[]          sdiff(array|string $keys)
 * @method int               sdiffstore(string $destination, array|string $keys)
 * @method string[]          sinter(array|string $keys)
 * @method int               sintercard(array $keys, int $limit = 0)
 * @method int               sinterstore(string $destination, array|string $keys)
 * @method int               sismember(string $key, string $member)
 * @method string[]          smembers(string $key)
 * @method array             smismember(string $key, string ...$members)
 * @method int               smove(string $source, string $destination, string $member)
 * @method string|array|null spop(string $key, int $count = null)
 * @method string|null       srandmember(string $key, int $count = null)
 * @method int               srem(string $key, array|string $member)
 * @method array             sscan(string $key, int $cursor, array $options = null)
 * @method string[]          sunion(array|string $keys)
 * @method int               sunionstore(string $destination, array|string $keys)
 * @method int               touch(string[]|string $keyOrKeys, string ...$keys = null)
 * @method Status            tdigestadd(string $key, float ...$value)
 * @method array             tdigestbyrank(string $key, int ...$rank)
 * @method array             tdigestbyrevrank(string $key, int ...$reverseRank)
 * @method array             tdigestcdf(string $key, int ...$value)
 * @method Status            tdigestcreate(string $key, int $compression = 0)
 * @method array             tdigestinfo(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 string            tdigestmin(string $key)
 * @method array             tdigestrank(string $key, float ...$value)
 * @method Status            tdigestreset(string $key)
 * @method array             tdigestrevrank(string $key, float ...$value)
 * @method string            tdigesttrimmed_mean(string $key, float $lowCutQuantile, float $highCutQuantile)
 * @method array             topkadd(string $key, ...$items)
 * @method array             topkincrby(string $key, ...$itemIncrement)
 * @method array             topkinfo(string $key)
 * @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, 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)
 * @method int               tsdecrby(string $key, float $value, ?DecrByArguments $arguments = null)
 * @method int               tsdel(string $key, int $fromTimestamp, int $toTimestamp)
 * @method Status            tsdeleterule(string $sourceKey, string $destKey)
 * @method array             tsget(string $key, GetArguments $arguments = null)
 * @method int               tsincrby(string $key, float $value, ?IncrByArguments $arguments = null)
 * @method array             tsinfo(string $key, ?InfoArguments $arguments = null)
 * @method array             tsmadd(mixed ...$keyTimestampValue)
 * @method array             tsmget(MGetArguments $arguments, string ...$filterExpression)
 * @method array             tsmrange($fromTimestamp, $toTimestamp, MRangeArguments $arguments)
 * @method array             tsmrevrange($fromTimestamp, $toTimestamp, MRangeArguments $arguments)
 * @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 string            xadd(string $key, array $dictionary, string $id = '*', array $options = null)
 * @method int               xdel(string $key, string ...$id)
 * @method int               xlen(string $key)
 * @method array             xrevrange(string $key, string $end, string $start, ?int $count = null)
 * @method array             xrange(string $key, string $start, string $end, ?int $count = null)
 * @method string            xtrim(string $key, array|string $strategy, string $threshold, array $options = null)
 * @method int               zadd(string $key, array $membersAndScoresDictionary)
 * @method int               zcard(string $key)
 * @method string            zcount(string $key, int|string $min, int|string $max)
 * @method array             zdiff(array $keys, bool $withScores = false)
 * @method int               zdiffstore(string $destination, array $keys)
 * @method string            zincrby(string $key, int $increment, string $member)
 * @method int               zintercard(array $keys, int $limit = 0)
 * @method int               zinterstore(string $destination, array $keys, int[] $weights = [], string $aggregate = 'sum')
 * @method array             zinter(array $keys, int[] $weights = [], string $aggregate = 'sum', bool $withScores = false)
 * @method array             zmpop(array $keys, string $modifier = 'min', int $count = 1)
 * @method array             zmscore(string $key, string ...$member)
 * @method array             zpopmin(string $key, int $count = 1)
 * @method array             zpopmax(string $key, int $count = 1)
 * @method mixed             zrandmember(string $key, int $count = 1, bool $withScores = false)
 * @method array             zrange(string $key, int|string $start, int|string $stop, array $options = null)
 * @method array             zrangebyscore(string $key, int|string $min, int|string $max, array $options = null)
 * @method int               zrangestore(string $destination, string $source, int|string $min, int|string $max, string|bool $by = false, bool $reversed = false, bool $limit = false, int $offset = 0, int $count = 0)
 * @method int|null          zrank(string $key, string $member)
 * @method int               zrem(string $key, string ...$member)
 * @method int               zremrangebyrank(string $key, int|string $start, int|string $stop)
 * @method int               zremrangebyscore(string $key, int|string $min, int|string $max)
 * @method array             zrevrange(string $key, int|string $start, int|string $stop, array $options = null)
 * @method array             zrevrangebyscore(string $key, int|string $max, int|string $min, array $options = null)
 * @method int|null          zrevrank(string $key, string $member)
 * @method array             zunion(array $keys, int[] $weights = [], string $aggregate = 'sum', bool $withScores = false)
 * @method int               zunionstore(string $destination, array $keys, int[] $weights = [], string $aggregate = 'sum')
 * @method string|null       zscore(string $key, string $member)
 * @method array             zscan(string $key, int $cursor, array $options = null)
 * @method array             zrangebylex(string $key, string $start, string $stop, array $options = null)
 * @method array             zrevrangebylex(string $key, string $start, string $stop, array $options = null)
 * @method int               zremrangebylex(string $key, string $min, string $max)
 * @method int               zlexcount(string $key, string $min, string $max)
 * @method int               pexpiretime(string $key)
 * @method int               pfadd(string $key, array $elements)
 * @method mixed             pfmerge(string $destinationKey, array|string $sourceKeys)
 * @method int               pfcount(string[]|string $keyOrKeys, string ...$keys = null)
 * @method mixed             pubsub($subcommand, $argument)
 * @method int               publish($channel, $message)
 * @method mixed             discard()
 * @method array|null        exec()
 * @method mixed             multi()
 * @method mixed             unwatch()
 * @method array             waitaof(int $numLocal, int $numReplicas, int $timeout)
 * @method mixed             watch(string $key)
 * @method mixed             eval(string $script, int $numkeys, string ...$keyOrArg = null)
 * @method mixed             eval_ro(string $script, array $keys, ...$argument)
 * @method mixed             evalsha(string $script, int $numkeys, string ...$keyOrArg = null)
 * @method mixed             evalsha_ro(string $sha1, array $keys, ...$argument)
 * @method mixed             script($subcommand, $argument = null)
 * @method Status            shutdown(bool $noSave = null, bool $now = false, bool $force = false, bool $abort = false)
 * @method mixed             auth(string $password)
 * @method string            echo(string $message)
 * @method mixed             ping(string $message = null)
 * @method mixed             select(int $database)
 * @method mixed             bgrewriteaof()
 * @method mixed             bgsave()
 * @method mixed             client($subcommand, $argument = null)
 * @method mixed             config($subcommand, $argument = null)
 * @method int               dbsize()
 * @method mixed             flushall()
 * @method mixed             flushdb()
 * @method array             info($section = null)
 * @method int               lastsave()
 * @method mixed             save()
 * @method mixed             slaveof(string $host, int $port)
 * @method mixed             slowlog($subcommand, $argument = null)
 * @method array             time()
 * @method array             command()
 * @method int               geoadd(string $key, $longitude, $latitude, $member)
 * @method array             geohash(string $key, array $members)
 * @method array             geopos(string $key, array $members)
 * @method string|null       geodist(string $key, $member1, $member2, $unit = null)
 * @method array             georadius(string $key, $longitude, $latitude, $radius, $unit, array $options = null)
 * @method array             georadiusbymember(string $key, $member, $radius, $unit, array $options = null)
 * @method array             geosearch(string $key, FromInterface $from, ByInterface $by, ?string $sorting = null, int $count = -1, bool $any = false, bool $withCoord = false, bool $withDist = false, bool $withHash = false)
 * @method int               geosearchstore(string $destination, string $source, FromInterface $from, ByInterface $by, ?string $sorting = null, int $count = -1, bool $any = false, bool $storeDist = false)
 *
 * Container commands
 * @property CLUSTER           $cluster
 * @property FunctionContainer $function
 * @property FTCONFIG          $ftconfig
 * @property FTCURSOR          $ftcursor
 * @property JSONDEBUG         $jsondebug
 * @property ACL               $acl
 */
interface ClientInterface
{
    /**
     * Returns the command factory used by the client.
     *
     * @return FactoryInterface
     */
    public function getCommandFactory();

    /**
     * Returns the client options specified upon initialization.
     *
     * @return OptionsInterface
     */
    public function getOptions();

    /**
     * Opens the underlying connection to the server.
     */
    public function connect();

    /**
     * Closes the underlying connection from the server.
     */
    public function disconnect();

    /**
     * Returns the underlying connection instance.
     *
     * @return ConnectionInterface
     */
    public function getConnection();

    /**
     * Creates a new instance of the specified Redis command.
     *
     * @param string $method    Command ID.
     * @param array  $arguments Arguments for the command.
     *
     * @return CommandInterface
     */
    public function createCommand($method, $arguments = []);

    /**
     * Executes the specified Redis command.
     *
     * @param CommandInterface $command Command instance.
     *
     * @return mixed
     */
    public function executeCommand(CommandInterface $command);

    /**
     * Creates a Redis command with the specified arguments and sends a request
     * to the server.
     *
     * @param string $method    Command ID.
     * @param array  $arguments Arguments for the command.
     *
     * @return mixed
     */
    public function __call($method, $arguments);
}
                                                                                                                                                         predis/src/CommunicationException.php                                                               0000644                 00000004134 15233650113 0014017 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php

/*
 * This file is part of the Predis package.
 *
 * (c) 2009-2020 Daniele Alessandri
 * (c) 2021-2023 Till Krüss
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis;

use Exception;
use Predis\Connection\NodeConnectionInterface;

/**
 * Base exception class for network-related errors.
 */
abstract class CommunicationException extends PredisException
{
    private $connection;

    /**
     * @param NodeConnectionInterface $connection     Connection that generated the exception.
     * @param string                  $message        Error message.
     * @param int                     $code           Error code.
     * @param Exception|null          $innerException Inner exception for wrapping the original error.
     */
    public function __construct(
        NodeConnectionInterface $connection,
        $message = '',
        $code = 0,
        Exception $innerException = null
    ) {
        parent::__construct(
            is_null($message) ? '' : $message,
            is_null($code) ? 0 : $code,
            $innerException
        );

        $this->connection = $connection;
    }

    /**
     * Gets the connection that generated the exception.
     *
     * @return NodeConnectionInterface
     */
    public function getConnection()
    {
        return $this->connection;
    }

    /**
     * Indicates if the receiver should reset the underlying connection.
     *
     * @return bool
     */
    public function shouldResetConnection()
    {
        return true;
    }

    /**
     * Helper method to handle exceptions generated by a connection object.
     *
     * @param CommunicationException $exception Exception.
     *
     * @throws CommunicationException
     */
    public static function handle(CommunicationException $exception)
    {
        if ($exception->shouldResetConnection()) {
            $connection = $exception->getConnection();

            if ($connection->isConnected()) {
                $connection->disconnect();
            }
        }

        throw $exception;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    