Skip to content

Commit e11d89c

Browse files
committed
Add client for ReactPHP Redis
1 parent b2cef72 commit e11d89c

14 files changed

+145
-66
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased v2.x]
88

9+
### Added
10+
11+
- Add client for ReactPHP Redis
12+
913
### Changed
1014

1115
- (dev) Update PHP-CS-Fixer to version `3.12.0`

composer.json

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"ext-mbstring": "*",
3030
"amphp/redis": "^1.0",
3131
"cheprasov/php-redis-client": "^1.10",
32+
"clue/redis-react": "^2.6",
3233
"colinmollenhour/credis": "^1.12",
3334
"enlightn/security-checker": "^1.9",
3435
"ergebnis/composer-normalize": "^2.13",
@@ -41,6 +42,7 @@
4142
"phpunit/phpunit": "^8.5 || ^9.3",
4243
"predis/predis": "^1.1 || ^2.0",
4344
"ptrofimov/tinyredisclient": "^1.1",
45+
"react/async": "^3.0",
4446
"redisent/redisent": "dev-master",
4547
"roave/security-advisories": "dev-latest",
4648
"rskuipers/php-assumptions": "^0.8.0",

src/Redis/Client/AbstractClient.php

+12
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,18 @@ public function pipeline(Command ...$commands): array
4141
}, $results, array_keys($results));
4242
}
4343

44+
public function execute(Command $command)
45+
{
46+
$args = [$command->getId()];
47+
$commandArgs = $command->getArguments();
48+
if (count($commandArgs) > 0) {
49+
array_push($args, ...$commandArgs);
50+
}
51+
$result = $this->executeRaw(...$args);
52+
53+
return $command->parseResponse($result);
54+
}
55+
4456
/**
4557
* @return array<mixed>
4658
*/

src/Redis/Client/AmpRedisClient.php

+3-9
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,6 @@ public static function make($redis): Client
5353
return new self($redis);
5454
}
5555

56-
public function execute(Command $command)
57-
{
58-
/** @var Promise<mixed> $query */
59-
$query = $this->redis->query($command->getId(), ...array_map('strval', $command->getArguments()));
60-
$result = wait($query);
61-
62-
return $command->parseResponse($result);
63-
}
64-
6556
public function executeRaw(...$args)
6657
{
6758
/** @var Promise<mixed> $query */
@@ -77,6 +68,9 @@ public static function supports($redis): bool
7768
&& function_exists('\\Amp\\Promise\\wait');
7869
}
7970

71+
/**
72+
* @codeCoverageIgnore
73+
*/
8074
public function pipeline(Command ...$commands): array
8175
{
8276
false === static::$disableNotice

src/Redis/Client/CheprasovRedisClient.php

-7
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,6 @@ public static function make($redis): Client
5252
return new self($redis);
5353
}
5454

55-
public function execute(Command $command)
56-
{
57-
$response = $this->redis->executeRaw(array_merge([$command->getId()], $command->getArguments()));
58-
59-
return $command->parseResponse($response);
60-
}
61-
6255
public function executeRaw(...$args)
6356
{
6457
return $this->redis->executeRaw(array_map('strval', $args));

src/Redis/Client/ClientFacade.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
namespace MacFJA\RediSearch\Redis\Client;
2323

2424
use Amp\Redis\Redis as AmpRedis;
25+
use Clue\React\Redis\Client as ReactClient;
2526
use Credis_Client as CredisRedis;
2627
use MacFJA\RediSearch\Redis\Client;
2728
use Predis\ClientInterface as PredisRedis;
29+
use React\Promise\Promise as ReactPromise;
2830
use Redis as PhpredisRedis;
2931
use RedisClient\Client\AbstractRedisClient as CheprasovRedis;
3032
use redisent\Redis as RedisentRedis;
@@ -44,10 +46,11 @@ class ClientFacade
4446
RediskaClient::class,
4547
AmpRedisClient::class,
4648
TinyRedisClient::class,
49+
ReactRedisClient::class,
4750
];
4851

4952
/**
50-
* @param AmpRedis|CheprasovRedis|CredisRedis|mixed|PhpredisRedis|PredisRedis|RedisentRedis|RediskaRedis|resource $redis
53+
* @param AmpRedis|CheprasovRedis|CredisRedis|mixed|PhpredisRedis|PredisRedis|ReactClient|ReactPromise|RedisentRedis|RediskaRedis|resource $redis
5154
*/
5255
public function getClient($redis): Client
5356
{

src/Redis/Client/CredisClient.php

-7
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,6 @@ public static function make($redis): Client
5151
return new self($redis);
5252
}
5353

54-
public function execute(Command $command)
55-
{
56-
$result = $this->redis->__call($command->getId(), $command->getArguments());
57-
58-
return $command->parseResponse($this->fixFalseToNull($result));
59-
}
60-
6154
public function executeRaw(...$args)
6255
{
6356
$command = array_shift($args);

src/Redis/Client/PhpiredisClient.php

-7
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,6 @@ private function __construct($redis)
5151
$this->redis = $redis;
5252
}
5353

54-
public function execute(Command $command)
55-
{
56-
$rawResponse = phpiredis_command_bs($this->redis, array_merge([$command->getId()], $command->getArguments()));
57-
58-
return $command->parseResponse($rawResponse);
59-
}
60-
6154
public static function supports($redis): bool
6255
{
6356
if (!is_resource($redis)

src/Redis/Client/PredisClient.php

-7
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,6 @@ private function __construct(ClientInterface $redis)
5555
$this->redis = $redis;
5656
}
5757

58-
public function execute(Command $command)
59-
{
60-
$rawResponse = $this->redis->executeCommand(self::createRawCommand(array_merge([$command->getId()], $command->getArguments())));
61-
62-
return $command->parseResponse($rawResponse);
63-
}
64-
6558
public static function supports($redis): bool
6659
{
6760
if (

src/Redis/Client/ReactRedisClient.php

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* Copyright MacFJA
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
9+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
10+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
11+
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
14+
* Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17+
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
*/
21+
22+
namespace MacFJA\RediSearch\Redis\Client;
23+
24+
use function function_exists;
25+
use function React\Async\await;
26+
27+
use Clue\React\Redis\Client;
28+
use MacFJA\RediSearch\Redis\Command;
29+
use React\Promise\Promise;
30+
use React\Promise\PromiseInterface;
31+
use RuntimeException;
32+
33+
class ReactRedisClient extends AbstractClient
34+
{
35+
/**
36+
* @var Client
37+
*/
38+
private $redis;
39+
40+
/**
41+
* @codeCoverageIgnore
42+
*
43+
* @param mixed $redis
44+
*/
45+
private function __construct($redis)
46+
{
47+
if (!static::supports($redis)) {
48+
throw new RuntimeException($this->getMissingMessage('Clue Redis React and/or React\\Async', false, [
49+
Client::class => [],
50+
PromiseInterface::class => [],
51+
], ['\React\Async\await']));
52+
}
53+
if ($redis instanceof Promise) {
54+
$realRedis = await($redis);
55+
if (!$realRedis instanceof Client) {
56+
throw new RuntimeException('The provided $redis parameter is not a valid Redis client');
57+
}
58+
$this->redis = $realRedis;
59+
60+
return;
61+
}
62+
$this->redis = $redis;
63+
}
64+
65+
/**
66+
* @codeCoverageIgnore
67+
*/
68+
public function pipeline(Command ...$commands): array
69+
{
70+
false === static::$disableNotice
71+
&& trigger_error('Warning, Clue\\React\\Redis\\Client don\'t use a real Redis Pipeline', E_USER_NOTICE);
72+
73+
return array_map(function (Command $command) {
74+
return $this->execute($command);
75+
}, $commands);
76+
}
77+
78+
public static function make($redis): \MacFJA\RediSearch\Redis\Client
79+
{
80+
return new self($redis);
81+
}
82+
83+
public function executeRaw(...$args)
84+
{
85+
$command = array_shift($args);
86+
87+
return await($this->redis->__call((string) $command, array_map('strval', $args)));
88+
}
89+
90+
public static function supports($redis): bool
91+
{
92+
return ($redis instanceof Client || $redis instanceof PromiseInterface) && function_exists('\React\Async\await');
93+
}
94+
95+
/**
96+
* @codeCoverageIgnore
97+
*/
98+
protected function doPipeline(Command ...$commands): array
99+
{
100+
return [];
101+
}
102+
}

src/Redis/Client/RedisentClient.php

-7
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,6 @@ public static function make($redis): Client
4949
return new self($redis);
5050
}
5151

52-
public function execute(Command $command)
53-
{
54-
$result = $this->redis->__call($command->getId(), $command->getArguments());
55-
56-
return $command->parseResponse($result);
57-
}
58-
5952
public function executeRaw(...$args)
6053
{
6154
$command = array_shift($args);

src/Redis/Client/TinyRedisClient.php

-7
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,6 @@ public function pipeline(Command ...$commands): array
5555
}, $commands);
5656
}
5757

58-
public function execute(Command $command)
59-
{
60-
$result = $this->redis->__call($command->getId(), $command->getArguments());
61-
62-
return $command->parseResponse($result);
63-
}
64-
6558
public function executeRaw(...$args)
6659
{
6760
$command = array_shift($args);

tests/Redis/Client/ClientFacadeTest.php

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
* @uses \MacFJA\RediSearch\Redis\Client\RediskaClient
4242
* @uses \MacFJA\RediSearch\Redis\Client\CredisClient
4343
* @uses \MacFJA\RediSearch\Redis\Client\TinyRedisClient
44+
* @uses \MacFJA\RediSearch\Redis\Client\ReactRedisClient
4445
*
4546
* @internal
4647
*/

tests/integration/DockerTest.php

+17-14
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
* @covers \MacFJA\RediSearch\Redis\Client\ClientFacade
6060
* @covers \MacFJA\RediSearch\Redis\Client\CredisClient
6161
* @covers \MacFJA\RediSearch\Redis\Client\PredisClient
62+
* @covers \MacFJA\RediSearch\Redis\Client\ReactRedisClient
6263
* @covers \MacFJA\RediSearch\Redis\Client\RedisentClient
6364
* @covers \MacFJA\RediSearch\Redis\Client\RediskaClient
6465
* @covers \MacFJA\RediSearch\Redis\Client\TinyRedisClient
@@ -277,24 +278,26 @@ public function dataProvider(string $testName): array
277278
{
278279
if (in_array($testName, ['testIntegration', 'testAddDocument'])) {
279280
return [
280-
[static function () { return Client\PredisClient::make(new \Predis\Client(['scheme' => 'tcp', 'host' => 'localhost', 'port' => '16379', 'db' => 0])); }],
281-
[static function () { return Client\RediskaClient::make(new Rediska(['servers' => [['host' => 'localhost', 'port' => '16379', 'db' => 0]]])); }],
282-
[static function () { return Client\RedisentClient::make(new \redisent\Redis('redis://localhost:16379')); }],
283-
[static function () { return Client\CheprasovRedisClient::make(new \RedisClient\Client\Version\RedisClient6x0(['server' => 'localhost:16379', 'database' => 0])); }],
284-
[static function () { return Client\AmpRedisClient::make(new \Amp\Redis\Redis(new RemoteExecutor(Config::fromUri('redis://localhost:16379')))); }],
285-
[static function () { return Client\TinyRedisClient::make(new TinyRedisClient('localhost:16379')); }],
286-
[static function () { return Client\CredisClient::make(new Credis_Client('localhost', 16379, null, '', 0)); }],
281+
'Predis' => [static function () { return Client\PredisClient::make(new \Predis\Client(['scheme' => 'tcp', 'host' => 'localhost', 'port' => '16379', 'db' => 0])); }],
282+
'Rediska' => [static function () { return Client\RediskaClient::make(new Rediska(['servers' => [['host' => 'localhost', 'port' => '16379', 'db' => 0]]])); }],
283+
'Redisent' => [static function () { return Client\RedisentClient::make(new \redisent\Redis('redis://localhost:16379')); }],
284+
'CheprasovRedis' => [static function () { return Client\CheprasovRedisClient::make(new \RedisClient\Client\Version\RedisClient6x0(['server' => 'localhost:16379', 'database' => 0])); }],
285+
'AmpRedis' => [static function () { return Client\AmpRedisClient::make(new \Amp\Redis\Redis(new RemoteExecutor(Config::fromUri('redis://localhost:16379')))); }],
286+
'TinyRedis' => [static function () { return Client\TinyRedisClient::make(new TinyRedisClient('localhost:16379')); }],
287+
'Credis' => [static function () { return Client\CredisClient::make(new Credis_Client('localhost', 16379, null, '', 0)); }],
288+
'ReactRedis' => [static function () { return Client\ReactRedisClient::make((new \Clue\React\Redis\Factory())->createClient('localhost:16379')); }],
287289
];
288290
}
289291

290292
return [
291-
[Client\PredisClient::class, static function () { return new \Predis\Client(['scheme' => 'tcp', 'host' => 'localhost', 'port' => '16379', 'db' => 0]); }],
292-
[Client\RediskaClient::class, static function () { return new Rediska(['servers' => [['host' => 'localhost', 'port' => '16379', 'db' => 0]]]); }],
293-
[Client\RedisentClient::class, static function () { return new \redisent\Redis('redis://localhost:16379'); }],
294-
[Client\CheprasovRedisClient::class, static function () { return new \RedisClient\Client\Version\RedisClient6x0(['server' => 'localhost:16379', 'database' => 0]); }],
295-
[Client\AmpRedisClient::class, static function () { return new \Amp\Redis\Redis(new RemoteExecutor(Config::fromUri('redis://localhost:16379'))); }],
296-
[Client\TinyRedisClient::class, static function () { return new TinyRedisClient('localhost:16379'); }],
297-
[Client\CredisClient::class, static function () { return new Credis_Client('localhost', 16379, null, '', 0); }],
293+
'Predis' => [Client\PredisClient::class, static function () { return new \Predis\Client(['scheme' => 'tcp', 'host' => 'localhost', 'port' => '16379', 'db' => 0]); }],
294+
'Rediska' => [Client\RediskaClient::class, static function () { return new Rediska(['servers' => [['host' => 'localhost', 'port' => '16379', 'db' => 0]]]); }],
295+
'Redisent' => [Client\RedisentClient::class, static function () { return new \redisent\Redis('redis://localhost:16379'); }],
296+
'CheprasovRedis' => [Client\CheprasovRedisClient::class, static function () { return new \RedisClient\Client\Version\RedisClient6x0(['server' => 'localhost:16379', 'database' => 0]); }],
297+
'AmpRedis' => [Client\AmpRedisClient::class, static function () { return new \Amp\Redis\Redis(new RemoteExecutor(Config::fromUri('redis://localhost:16379'))); }],
298+
'TinyRedis' => [Client\TinyRedisClient::class, static function () { return new TinyRedisClient('localhost:16379'); }],
299+
'Credis' => [Client\CredisClient::class, static function () { return new Credis_Client('localhost', 16379, null, '', 0); }],
300+
'ReactRedis' => [Client\ReactRedisClient::class, static function () { return (new \Clue\React\Redis\Factory())->createClient('localhost:16379'); }],
298301
];
299302
}
300303

0 commit comments

Comments
 (0)