mirror of
https://github.com/predis/predis.git
synced 2026-09-11 10:57:00 +00:00
Merge branch 'main' of https://github.com/predis/predis
This commit is contained in:
@@ -12,8 +12,8 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\ClientConfiguration;
|
||||
use Predis\Command\Redis\FUNCTIONS;
|
||||
use Predis\Command\Resolver\CommandResolverInterface;
|
||||
|
||||
/**
|
||||
* Command factory for mainline Redis servers.
|
||||
@@ -26,12 +26,9 @@ use Predis\Command\Resolver\CommandResolverInterface;
|
||||
*/
|
||||
class RedisFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* @var CommandResolverInterface
|
||||
*/
|
||||
private $commandResolver;
|
||||
private const COMMANDS_NAMESPACE = "Predis\Command\Redis";
|
||||
|
||||
public function __construct(CommandResolverInterface $commandResolver)
|
||||
public function __construct()
|
||||
{
|
||||
$this->commands = [
|
||||
'ECHO' => 'Predis\Command\Redis\ECHO_',
|
||||
@@ -40,8 +37,6 @@ class RedisFactory extends Factory
|
||||
// Class name corresponds to PHP reserved word "function", added mapping to bypass restrictions
|
||||
'FUNCTION' => FUNCTIONS::class,
|
||||
];
|
||||
|
||||
$this->commandResolver = $commandResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,7 +50,7 @@ class RedisFactory extends Factory
|
||||
return $this->commands[$commandID];
|
||||
}
|
||||
|
||||
$commandClass = $this->commandResolver->resolve($commandID);
|
||||
$commandClass = $this->resolve($commandID);
|
||||
|
||||
if (null === $commandClass) {
|
||||
return null;
|
||||
@@ -78,4 +73,40 @@ class RedisFactory extends Factory
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Resolver;
|
||||
|
||||
use Predis\ClientConfiguration;
|
||||
|
||||
class CommandResolver implements CommandResolverInterface
|
||||
{
|
||||
private const COMMANDS_NAMESPACE = "Predis\Command\Redis";
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $modules;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->modules = ClientConfiguration::getModules();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public 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 ($this->modules as $module) {
|
||||
if (preg_match("/^{$module['commandPrefix']}/", $commandID)) {
|
||||
return $module['name'];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Resolver;
|
||||
|
||||
interface CommandResolverInterface
|
||||
{
|
||||
/**
|
||||
* Resolves command object from given command ID.
|
||||
*
|
||||
* @param string $commandID Command ID of virtual method call
|
||||
* @return string FQDN of corresponding command object
|
||||
*/
|
||||
public function resolve(string $commandID): ?string;
|
||||
}
|
||||
@@ -16,7 +16,6 @@ use InvalidArgumentException;
|
||||
use Predis\Command\FactoryInterface;
|
||||
use Predis\Command\RawFactory;
|
||||
use Predis\Command\RedisFactory;
|
||||
use Predis\Command\Resolver\CommandResolver;
|
||||
use Predis\Configuration\OptionInterface;
|
||||
use Predis\Configuration\OptionsInterface;
|
||||
|
||||
@@ -136,7 +135,7 @@ class Commands implements OptionInterface
|
||||
*/
|
||||
public function getDefault(OptionsInterface $options)
|
||||
{
|
||||
$commands = new RedisFactory(new CommandResolver());
|
||||
$commands = new RedisFactory();
|
||||
|
||||
if (isset($options->prefix)) {
|
||||
$commands->setProcessor($options->prefix);
|
||||
|
||||
@@ -167,9 +167,7 @@ abstract class PredisTestCase extends \PHPUnit\Framework\TestCase
|
||||
protected function getDefaultOptionsArray(): array
|
||||
{
|
||||
return [
|
||||
'commands' => new Command\RedisFactory(
|
||||
new Command\Resolver\CommandResolver()
|
||||
),
|
||||
'commands' => new Command\RedisFactory(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -209,7 +207,7 @@ abstract class PredisTestCase extends \PHPUnit\Framework\TestCase
|
||||
*/
|
||||
protected function getCommandFactory(): Command\Factory
|
||||
{
|
||||
return new Command\RedisFactory(new Command\Resolver\CommandResolver());
|
||||
return new Command\RedisFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -60,21 +60,19 @@ class JSONDEBUG_Test extends PredisCommandTestCase
|
||||
* @param array $jsonArguments
|
||||
* @param string $key
|
||||
* @param string $path
|
||||
* @param array $expectedMemoryUsage
|
||||
* @return void
|
||||
* @requiresRedisJsonVersion >= 1.0.0
|
||||
*/
|
||||
public function testMemoryReturnsCorrectMemoryUsageAboutJson(
|
||||
array $jsonArguments,
|
||||
string $key,
|
||||
string $path,
|
||||
array $expectedMemoryUsage
|
||||
string $path
|
||||
): void {
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->jsonset(...$jsonArguments);
|
||||
|
||||
$this->assertSame($expectedMemoryUsage, $redis->jsondebug->memory($key, $path));
|
||||
$this->assertGreaterThan(0, $redis->jsondebug->memory($key, $path));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,31 +97,26 @@ class JSONDEBUG_Test extends PredisCommandTestCase
|
||||
['key', '$', '{"key1":"value1","key2":"value2"}'],
|
||||
'key',
|
||||
'$',
|
||||
[44],
|
||||
],
|
||||
'on nested level' => [
|
||||
['key', '$', '{"key1":{"key2":"value2"}}'],
|
||||
'key',
|
||||
'$..key2',
|
||||
[14],
|
||||
],
|
||||
'with same keys on both levels' => [
|
||||
['key', '$', '{"key1":{"key2":"value2"},"key2":"value2"}'],
|
||||
'key',
|
||||
'$..key2',
|
||||
[14, 14],
|
||||
],
|
||||
'with wrong key' => [
|
||||
['key', '$', '{"key1":{"key2":"value2"}}'],
|
||||
'key1',
|
||||
'$',
|
||||
[],
|
||||
],
|
||||
'with wrong path' => [
|
||||
['key', '$', '{"key1":{"key2":"value2"}}'],
|
||||
'key',
|
||||
'$.key3',
|
||||
[],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ namespace Predis\Command;
|
||||
|
||||
use Predis\Command\Processor\ProcessorChain;
|
||||
use Predis\Command\Processor\ProcessorInterface;
|
||||
use Predis\Command\Resolver\CommandResolver;
|
||||
use PredisTestCase;
|
||||
|
||||
class RedisFactoryTest extends PredisTestCase
|
||||
@@ -24,7 +23,7 @@ class RedisFactoryTest extends PredisTestCase
|
||||
*/
|
||||
public function testSupportedCommands(): void
|
||||
{
|
||||
$factory = new RedisFactory(new CommandResolver());
|
||||
$factory = new RedisFactory();
|
||||
|
||||
foreach ($this->getExpectedCommands() as $commandID) {
|
||||
$this->assertTrue($factory->supports($commandID), "Command factory does not support $commandID");
|
||||
@@ -36,7 +35,7 @@ class RedisFactoryTest extends PredisTestCase
|
||||
*/
|
||||
public function testSupportCommand(): void
|
||||
{
|
||||
$factory = new RedisFactory(new CommandResolver());
|
||||
$factory = new RedisFactory();
|
||||
|
||||
$this->assertTrue($factory->supports('info'));
|
||||
$this->assertTrue($factory->supports('INFO'));
|
||||
@@ -50,7 +49,7 @@ class RedisFactoryTest extends PredisTestCase
|
||||
*/
|
||||
public function testSupportCommands(): void
|
||||
{
|
||||
$factory = new RedisFactory(new CommandResolver());
|
||||
$factory = new RedisFactory();
|
||||
|
||||
$this->assertTrue($factory->supports('get', 'set'));
|
||||
$this->assertTrue($factory->supports('GET', 'SET'));
|
||||
@@ -65,7 +64,7 @@ class RedisFactoryTest extends PredisTestCase
|
||||
*/
|
||||
public function testGetCommandClass(): void
|
||||
{
|
||||
$factory = new RedisFactory(new CommandResolver());
|
||||
$factory = new RedisFactory();
|
||||
|
||||
$this->assertSame('Predis\Command\Redis\PING', $factory->getCommandClass('ping'));
|
||||
$this->assertSame('Predis\Command\Redis\PING', $factory->getCommandClass('PING'));
|
||||
@@ -79,7 +78,7 @@ class RedisFactoryTest extends PredisTestCase
|
||||
*/
|
||||
public function testDefineCommand(): void
|
||||
{
|
||||
$factory = new RedisFactory(new CommandResolver());
|
||||
$factory = new RedisFactory();
|
||||
|
||||
$command = $this->getMockBuilder('Predis\Command\CommandInterface')
|
||||
->getMock();
|
||||
@@ -97,7 +96,7 @@ class RedisFactoryTest extends PredisTestCase
|
||||
*/
|
||||
public function testUndefineCommandInClassAutoload(): void
|
||||
{
|
||||
$factory = new RedisFactory(new CommandResolver());
|
||||
$factory = new RedisFactory();
|
||||
|
||||
$this->assertTrue($factory->supports('PING'));
|
||||
$this->assertSame('Predis\Command\Redis\PING', $factory->getCommandClass('PING'));
|
||||
@@ -113,7 +112,7 @@ class RedisFactoryTest extends PredisTestCase
|
||||
*/
|
||||
public function testUndefineCommandInClassMap(): void
|
||||
{
|
||||
$factory = new RedisFactory(new CommandResolver());
|
||||
$factory = new RedisFactory();
|
||||
|
||||
$commandClass = get_class($this->getMockBuilder('Predis\Command\CommandInterface')->getMock());
|
||||
$factory->define('MOCK', $commandClass);
|
||||
@@ -135,7 +134,7 @@ class RedisFactoryTest extends PredisTestCase
|
||||
$this->expectException('InvalidArgumentException');
|
||||
$this->expectExceptionMessage("Class stdClass must implement Predis\Command\CommandInterface");
|
||||
|
||||
$factory = new RedisFactory(new CommandResolver());
|
||||
$factory = new RedisFactory();
|
||||
|
||||
$factory->define('mock', 'stdClass');
|
||||
}
|
||||
@@ -145,7 +144,7 @@ class RedisFactoryTest extends PredisTestCase
|
||||
*/
|
||||
public function testCreateCommandWithoutArguments(): void
|
||||
{
|
||||
$factory = new RedisFactory(new CommandResolver());
|
||||
$factory = new RedisFactory();
|
||||
|
||||
$command = $factory->create('info');
|
||||
|
||||
@@ -159,7 +158,7 @@ class RedisFactoryTest extends PredisTestCase
|
||||
*/
|
||||
public function testCreateCommandWithArguments(): void
|
||||
{
|
||||
$factory = new RedisFactory(new CommandResolver());
|
||||
$factory = new RedisFactory();
|
||||
|
||||
$arguments = ['foo', 'bar'];
|
||||
$command = $factory->create('set', $arguments);
|
||||
@@ -177,7 +176,7 @@ class RedisFactoryTest extends PredisTestCase
|
||||
$this->expectException('Predis\ClientException');
|
||||
$this->expectExceptionMessage('Command `UNKNOWN` is not a registered Redis command.');
|
||||
|
||||
$factory = new RedisFactory(new CommandResolver());
|
||||
$factory = new RedisFactory();
|
||||
|
||||
$factory->create('unknown');
|
||||
}
|
||||
@@ -187,7 +186,7 @@ class RedisFactoryTest extends PredisTestCase
|
||||
*/
|
||||
public function testGetDefaultProcessor(): void
|
||||
{
|
||||
$factory = new RedisFactory(new CommandResolver());
|
||||
$factory = new RedisFactory();
|
||||
|
||||
$this->assertNull($factory->getProcessor());
|
||||
}
|
||||
@@ -202,7 +201,7 @@ class RedisFactoryTest extends PredisTestCase
|
||||
->getMockBuilder('Predis\Command\Processor\ProcessorInterface')
|
||||
->getMock();
|
||||
|
||||
$factory = new RedisFactory(new CommandResolver());
|
||||
$factory = new RedisFactory();
|
||||
$factory->setProcessor($processor);
|
||||
|
||||
$this->assertSame($processor, $factory->getProcessor());
|
||||
@@ -218,7 +217,7 @@ class RedisFactoryTest extends PredisTestCase
|
||||
->getMockBuilder('Predis\Command\Processor\ProcessorInterface')
|
||||
->getMock();
|
||||
|
||||
$factory = new RedisFactory(new CommandResolver());
|
||||
$factory = new RedisFactory();
|
||||
|
||||
$factory->setProcessor($processor);
|
||||
$this->assertSame($processor, $factory->getProcessor());
|
||||
@@ -250,7 +249,7 @@ class RedisFactoryTest extends PredisTestCase
|
||||
}
|
||||
);
|
||||
|
||||
$factory = new RedisFactory(new CommandResolver());
|
||||
$factory = new RedisFactory();
|
||||
$factory->setProcessor($processor);
|
||||
$factory->create('set', ['foo', 'bar']);
|
||||
|
||||
@@ -274,7 +273,7 @@ class RedisFactoryTest extends PredisTestCase
|
||||
$chain->add($processor);
|
||||
$chain->add($processor);
|
||||
|
||||
$factory = new RedisFactory(new CommandResolver());
|
||||
$factory = new RedisFactory();
|
||||
$factory->setProcessor($chain);
|
||||
|
||||
$factory->create('info');
|
||||
@@ -451,6 +450,95 @@ class RedisFactoryTest extends PredisTestCase
|
||||
156 => 'GEODIST',
|
||||
157 => 'GEORADIUS',
|
||||
158 => 'GEORADIUSBYMEMBER',
|
||||
159 => 'JSONSET',
|
||||
160 => 'JSONGET',
|
||||
161 => 'JSONARRAPPEND',
|
||||
162 => 'JSONARRINDEX',
|
||||
163 => 'JSONARRINSERT',
|
||||
164 => 'JSONARRLEN',
|
||||
165 => 'JSONARRPOP',
|
||||
166 => 'JSONARRTRIM',
|
||||
167 => 'JSONCLEAR',
|
||||
168 => 'JSONDEBUG',
|
||||
169 => 'JSONDEL',
|
||||
170 => 'JSONFORGET',
|
||||
171 => 'JSONMGET',
|
||||
172 => 'JSONNUMINCRBY',
|
||||
173 => 'JSONOBJKEYS',
|
||||
174 => 'JSONOBJLEN',
|
||||
175 => 'JSONRESP',
|
||||
176 => 'JSONSTRAPPEND',
|
||||
177 => 'JSONSTRLEN',
|
||||
178 => 'JSONTOGGLE',
|
||||
179 => 'JSONTYPE',
|
||||
180 => 'BFADD',
|
||||
181 => 'BFEXISTS',
|
||||
182 => 'BFINFO',
|
||||
183 => 'BFINSERT',
|
||||
184 => 'BFLOADCHUNK',
|
||||
185 => 'BFMADD',
|
||||
186 => 'BFMEXISTS',
|
||||
187 => 'BFRESERVE',
|
||||
188 => 'BFSCANDUMP',
|
||||
189 => 'CMSINCRBY',
|
||||
190 => 'CMSINFO',
|
||||
191 => 'CMSINITBYDIM',
|
||||
192 => 'CMSINITBYPROB',
|
||||
193 => 'CMSMERGE',
|
||||
194 => 'CMSQUERY',
|
||||
195 => 'CFADD',
|
||||
196 => 'CFADDNX',
|
||||
197 => 'CFCOUNT',
|
||||
198 => 'CFDEL',
|
||||
199 => 'CFEXISTS',
|
||||
200 => 'CFINFO',
|
||||
201 => 'CFINSERT',
|
||||
202 => 'CFINSERTNX',
|
||||
203 => 'CFLOADCHUNK',
|
||||
204 => 'CFMEXISTS',
|
||||
205 => 'CFRESERVE',
|
||||
206 => 'CFSCANDUMP',
|
||||
207 => 'TDIGESTADD',
|
||||
208 => 'TDIGESTBYRANK',
|
||||
209 => 'TDIGESTBYREVRANK',
|
||||
210 => 'TDIGESTCDF',
|
||||
211 => 'TDIGESTCREATE',
|
||||
212 => 'TDIGESTINFO',
|
||||
213 => 'TDIGESTMAX',
|
||||
214 => 'TDIGESTMERGE',
|
||||
215 => 'TDIGESTMIN',
|
||||
216 => 'TDIGESTQUANTILE',
|
||||
217 => 'TDIGESTRANK',
|
||||
218 => 'TDIGESTRESET',
|
||||
219 => 'TDIGESTREVRANK',
|
||||
220 => 'TDIGESTTRIMMED_MEAN',
|
||||
221 => 'TOPKADD',
|
||||
222 => 'TOPKINCRBY',
|
||||
223 => 'TOPKINFO',
|
||||
224 => 'TOPKLIST',
|
||||
225 => 'TOPKQUERY',
|
||||
226 => 'TOPKRESERVE',
|
||||
227 => 'FTALIASADD',
|
||||
228 => 'FTALIASDEL',
|
||||
229 => 'FTALIASUPDATE',
|
||||
230 => 'FTALTER',
|
||||
231 => 'FTCONFIG',
|
||||
232 => 'FTCREATE',
|
||||
233 => 'FTDICTADD',
|
||||
234 => 'FTDICTDEL',
|
||||
235 => 'FTDICTDUMP',
|
||||
236 => 'FTDROPINDEX',
|
||||
237 => 'FTINFO',
|
||||
238 => 'FTPROFILE',
|
||||
239 => 'FTSEARCH',
|
||||
240 => 'FTSPELLCHECK',
|
||||
241 => 'FTSUGADD',
|
||||
242 => 'FTSUGDEL',
|
||||
243 => 'FTSUGGET',
|
||||
244 => 'FTSUGLEN',
|
||||
245 => 'FTSYNDUMP',
|
||||
246 => 'FTSYNUPDATE',
|
||||
247 => 'FTTAGVALS',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Resolver;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Predis\Command\Redis\SET;
|
||||
|
||||
class CommandResolverTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider commandsProvider
|
||||
* @param string $commandID
|
||||
* @param string|null $expectedCommandClass
|
||||
* @return void
|
||||
*/
|
||||
public function testResolveResolvesCorrectlyCommand(
|
||||
string $commandID,
|
||||
?string $expectedCommandClass
|
||||
): void {
|
||||
$resolver = new CommandResolver();
|
||||
|
||||
$this->assertSame($expectedCommandClass, $resolver->resolve($commandID));
|
||||
}
|
||||
|
||||
public function commandsProvider(): array
|
||||
{
|
||||
return [
|
||||
'core command exists' => ['SET', SET::class],
|
||||
'module not exist' => ['FOOBAR', null],
|
||||
'module exists, module command not exists' => ['JSONFOO', null],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,6 @@ namespace Predis\Configuration\Option;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Predis\Command\Processor\KeyPrefixProcessor;
|
||||
use Predis\Command\RedisFactory;
|
||||
use Predis\Command\Resolver\CommandResolver;
|
||||
use Predis\Configuration\OptionsInterface;
|
||||
use PredisTestCase;
|
||||
use stdClass;
|
||||
@@ -77,7 +76,7 @@ class CommandsTest extends PredisTestCase
|
||||
/** @var OptionsInterface */
|
||||
$options = $this->getMockBuilder('Predis\Configuration\OptionsInterface')->getMock();
|
||||
|
||||
$input = new RedisFactory(new CommandResolver());
|
||||
$input = new RedisFactory();
|
||||
|
||||
$commands = $option->filter($options, $input);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user