diff --git a/src/DependencyInjection/Configuration/Configuration.php b/src/DependencyInjection/Configuration/Configuration.php index 1ff7a08b..96df4cac 100644 --- a/src/DependencyInjection/Configuration/Configuration.php +++ b/src/DependencyInjection/Configuration/Configuration.php @@ -155,6 +155,8 @@ private function addClientsSection(ArrayNodeDefinition $rootNode): void ->booleanNode('iterable_multibulk')->defaultFalse()->end() ->booleanNode('throw_errors')->defaultTrue()->end() ->scalarNode('serialization')->defaultValue('default')->end() + ->scalarNode('compression')->defaultNull()->end() + ->integerNode('compression_level')->defaultNull()->end() ->scalarNode('cluster')->defaultNull()->end() ->booleanNode('array')->defaultFalse()->end() ->scalarNode('prefix')->defaultNull()->end() diff --git a/src/Factory/PhpredisClientFactory.php b/src/Factory/PhpredisClientFactory.php index 92871898..bed577a4 100644 --- a/src/Factory/PhpredisClientFactory.php +++ b/src/Factory/PhpredisClientFactory.php @@ -27,7 +27,9 @@ use function array_map; use function array_values; use function class_exists; +use function constant; use function count; +use function defined; use function get_class; use function implode; use function in_array; @@ -37,6 +39,7 @@ use function phpversion; use function spl_autoload_register; use function sprintf; +use function strtoupper; use function var_export; use function version_compare; @@ -235,6 +238,16 @@ private function createArrayClient(array $dsns, string $class, string $alias, ar $client->setOption(Redis::OPT_SERIALIZER, $this->loadSerializationType($options['serialization'])); } + if (isset($options['compression'])) { + /** @psalm-suppress InvalidArgument */ + $client->setOption(Redis::OPT_COMPRESSION, $this->loadCompressionType($options['compression'])); + } + + if (isset($options['compression_level'])) { + /** @psalm-suppress InvalidArgument */ + $client->setOption(Redis::OPT_COMPRESSION_LEVEL, $options['compression_level']); + } + return $loggingEnabled ? $this->createLoggingProxy($client, $alias) : $client; } @@ -286,6 +299,14 @@ private function createClusterClient(array $dsns, string $class, string $alias, $client->setOption(Redis::OPT_SERIALIZER, $this->loadSerializationType($options['serialization'])); } + if (isset($options['compression'])) { + $client->setOption(Redis::OPT_COMPRESSION, $this->loadCompressionType($options['compression'])); + } + + if (isset($options['compression_level'])) { + $client->setOption(Redis::OPT_COMPRESSION_LEVEL, $options['compression_level']); + } + if (isset($options['slave_failover'])) { $client->setOption(RedisCluster::OPT_SLAVE_FAILOVER, $this->loadSlaveFailoverType($options['slave_failover'])); } @@ -365,6 +386,14 @@ private function createClient(RedisDsn $dsn, string $class, string $alias, array $client->setOption($class::OPT_SERIALIZER, $this->loadSerializationType($options['serialization'])); } + if (isset($options['compression'])) { + $client->setOption($class::OPT_COMPRESSION, $this->loadCompressionType($options['compression'])); + } + + if (isset($options['compression_level'])) { + $client->setOption($class::OPT_COMPRESSION_LEVEL, $options['compression_level']); + } + return $client; } @@ -387,6 +416,18 @@ private function loadSerializationType(string $type): int throw new InvalidConfigurationException(sprintf('%s in not a valid serializer. Valid serializers: %s', $type, implode(', ', array_keys($types)))); } + /** @throws InvalidConfigurationException */ + private function loadCompressionType(string $type): int + { + $const = 'Redis::COMPRESSION_' . strtoupper($type); + + if (!defined($const)) { + throw new InvalidConfigurationException(sprintf('"%s" is not a valid compression type.', $type)); + } + + return (int) constant($const); + } + private function loadSlaveFailoverType(string $type): int { $types = [ diff --git a/tests/DependencyInjection/SncRedisExtensionEnvTest.php b/tests/DependencyInjection/SncRedisExtensionEnvTest.php index 8fcb3148..44590d83 100644 --- a/tests/DependencyInjection/SncRedisExtensionEnvTest.php +++ b/tests/DependencyInjection/SncRedisExtensionEnvTest.php @@ -63,6 +63,8 @@ public function testPredisDefaultParameterConfig(): void 'read_write_timeout' => null, 'iterable_multibulk' => false, 'serialization' => 'default', + 'compression' => null, + 'compression_level' => null, 'prefix' => null, 'service' => null, 'async_connect' => false, @@ -104,6 +106,8 @@ public function testPhpredisDefaultParameterConfig(string $config, string $class 'iterable_multibulk' => false, 'throw_errors' => true, 'serialization' => 'default', + 'compression' => null, + 'compression_level' => null, 'cluster' => null, 'prefix' => null, 'service' => null, @@ -146,6 +150,8 @@ public function testPhpredisFullConfig(): void 'read_write_timeout' => null, 'iterable_multibulk' => false, 'throw_errors' => true, + 'compression' => null, + 'compression_level' => null, 'cluster' => null, 'service' => null, ], @@ -185,6 +191,8 @@ public function testPhpredisWithAclConfig(): void 'scan' => Redis::SCAN_NORETRY, 'read_write_timeout' => null, 'serialization' => 'php', + 'compression' => null, + 'compression_level' => null, 'service' => null, 'throw_errors' => true, ], @@ -230,6 +238,8 @@ public function testPhpRedisClusterOption(): void 'iterable_multibulk' => false, 'throw_errors' => true, 'serialization' => 'default', + 'compression' => null, + 'compression_level' => null, 'prefix' => null, 'service' => null, ], @@ -260,6 +270,8 @@ public function testPhpRedisSentinelOption(): void 'iterable_multibulk' => false, 'throw_errors' => true, 'serialization' => 'default', + 'compression' => null, + 'compression_level' => null, 'cluster' => null, 'prefix' => null, ], @@ -290,6 +302,8 @@ public function testPhpRedisClusterOptionMultipleDsn(): void 'iterable_multibulk' => false, 'throw_errors' => true, 'serialization' => 'default', + 'compression' => null, + 'compression_level' => null, 'prefix' => null, 'service' => null, ], diff --git a/tests/DependencyInjection/SncRedisExtensionTest.php b/tests/DependencyInjection/SncRedisExtensionTest.php index 6bcfb253..7756bf27 100644 --- a/tests/DependencyInjection/SncRedisExtensionTest.php +++ b/tests/DependencyInjection/SncRedisExtensionTest.php @@ -279,6 +279,20 @@ public function testClientSerializationOption(): void $this->assertSame($options['serialization'], $masterParameters['serialization']); } + /** + * Test valid config of the compression option + */ + public function testClientCompressionOption(): void + { + $extension = new SncRedisExtension(); + $config = $this->parseYaml($this->getCompressionYamlConfig()); + $extension->load([$config], $container = $this->getContainer()); + + $defaultParameters = $container->getDefinition('snc_redis.default'); + $this->assertSame('lzf', $defaultParameters->getArgument(2)['compression']); + $this->assertSame(5, $defaultParameters->getArgument(2)['compression_level']); + } + /** * Test valid config of the single host sentinel replication option */ @@ -445,6 +459,20 @@ private function parseYaml(string $yaml): array return $parser->parse($yaml); } + private function getCompressionYamlConfig(): string + { + return <<<'EOF' +clients: + default: + type: phpredis + alias: default + dsn: redis://localhost + options: + compression: "lzf" + compression_level: 5 +EOF; + } + private function getSerializationYamlConfig(): string { return <<<'EOF' diff --git a/tests/Factory/PhpredisClientFactoryTest.php b/tests/Factory/PhpredisClientFactoryTest.php index b0e74137..0da4814a 100644 --- a/tests/Factory/PhpredisClientFactoryTest.php +++ b/tests/Factory/PhpredisClientFactoryTest.php @@ -12,6 +12,7 @@ use Redis; use RedisArray; use RedisCluster; +use ReflectionClass; use Relay\Relay; use SEEC\PhpUnit\Helper\ConsecutiveParams; use Snc\RedisBundle\Factory\PhpredisClientFactory; @@ -413,6 +414,59 @@ public static function serializationTypes(): array ]; } + /** @dataProvider compressionTypes */ + public function testLoadCompressionType(string $compressionType, int $compression): void + { + $factory = new PhpredisClientFactory(new RedisCallInterceptor($this->redisLogger)); + + $client = $factory->create( + Redis::class, + ['redis://localhost:6379'], + [ + 'compression' => $compressionType, + 'connection_timeout' => 5, + ], + 'default', + false, + ); + + self::assertSame($compression, $client->getOption(Redis::OPT_COMPRESSION)); + } + + public function testLoadCompressionTypeFail(): void + { + $factory = new PhpredisClientFactory(new RedisCallInterceptor($this->redisLogger)); + $this->expectException(InvalidConfigurationException::class); + + $factory->create( + Redis::class, + ['redis://localhost:6379'], + [ + 'compression' => 'unknown', + 'connection_timeout' => 5, + ], + 'default', + false, + ); + } + + /** @return list */ + public static function compressionTypes(): array + { + $r = new ReflectionClass(Redis::class); + $types = [['none', Redis::COMPRESSION_NONE]]; + + foreach (['lzf' => 'COMPRESSION_LZF', 'zstd' => 'COMPRESSION_ZSTD', 'lz4' => 'COMPRESSION_LZ4'] as $name => $const) { + if (!$r->hasConstant($const)) { + continue; + } + + $types[] = [$name, $r->getConstant($const)]; + } + + return $types; + } + public function testMethodsWithVariadicParameters(): void { $this->logger->method('debug')->with(...$this->withConsecutive(