Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: snc/SncRedisBundle
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 4.4.2
Choose a base ref
...
head repository: snc/SncRedisBundle
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 4.5.0
Choose a head ref
  • 4 commits
  • 21 files changed
  • 2 contributors

Commits on Dec 17, 2022

  1. Support predis 2 (#686)

    Closes #664
    franmomu authored Dec 17, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    515e544 View commit details
  2. Upgrade psalm to version 5

    franmomu authored and ostrolucky committed Dec 17, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    4751362 View commit details

Commits on Dec 31, 2022

  1. Add Relay\Relay support

    ostrolucky committed Dec 31, 2022
    Copy the full SHA
    1dd46f1 View commit details
  2. Copy the full SHA
    4c81b59 View commit details
8 changes: 8 additions & 0 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
@@ -80,6 +80,14 @@ jobs:
extensions: "${{ matrix.php-extensions }}"
ini-values: "zend.assertions=1, max_execution_time=30"

- name: "Install Relay"
run: |
curl -L "https://cachewerk.s3.amazonaws.com/relay/dev/relay-dev-php${{ matrix.php-version }}-debian-x86-64.tar.gz" | tar xz
cd relay-dev-php${{ matrix.php-version }}-debian-x86-64
sudo cp relay.ini $(php-config --ini-dir)
sudo cp relay-pkg.so $(php-config --extension-dir)/relay.so
sudo sed -i "s/00000000-0000-0000-0000-000000000000/$(cat /proc/sys/kernel/random/uuid)/" $(php-config --extension-dir)/relay.so
- name: "Install symfony/flex"
run: "composer require --no-progress --no-scripts --no-plugins symfony/flex"

8 changes: 8 additions & 0 deletions .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
@@ -20,6 +20,14 @@ jobs:
coverage: "none"
php-version: "7.4"

- name: "Install Relay"
run: |
curl -L "https://cachewerk.s3.amazonaws.com/relay/dev/relay-dev-php7.4-debian-x86-64.tar.gz" | tar xz
cd relay-dev-php7.4-debian-x86-64
sudo cp relay.ini $(php-config --ini-dir)
sudo cp relay-pkg.so $(php-config --extension-dir)/relay.so
sudo sed -i "s/00000000-0000-0000-0000-000000000000/$(cat /proc/sys/kernel/random/uuid)/" $(php-config --extension-dir)/relay.so
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v2"

6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
@@ -35,7 +35,7 @@
"friendsofphp/proxy-manager-lts": "^1.0.6",
"monolog/monolog": "*",
"phpunit/phpunit": "^8.5 || ^9.5",
"predis/predis": ">=1.1",
"predis/predis": "^2.0",
"symfony/browser-kit": "^4.4 || ^5.3 || ^6.0",
"symfony/cache": "^4.4 || ^5.3 || ^6.0",
"symfony/console": "^4.4 || ^5.3 || ^6.0",
@@ -47,7 +47,7 @@
"symfony/stopwatch": "^4.4 || ^5.3 || ^6.0",
"symfony/twig-bundle": "^4.4 || ^5.3 || ^6.0",
"symfony/yaml": "^4.4 || ^5.3 || ^6.0",
"vimeo/psalm": "^4.13"
"vimeo/psalm": "^5.2"
},
"suggest": {
"monolog/monolog": "If you want to use the monolog redis handler.",
@@ -64,7 +64,7 @@
},
"conflict": {
"ext-redis": "<5.3",
"predis/predis": "<1.1 || >=2.0"
"predis/predis": "<2.0 || >=3.0"
},
"extra": {
"branch-alias": {
16 changes: 4 additions & 12 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

## About ##

This bundle integrates [Predis](https://github.com/nrk/predis) and [phpredis](https://github.com/nicolasff/phpredis) into your Symfony application.
This bundle integrates [Predis](https://github.com/nrk/predis), [PhpRedis](https://github.com/nicolasff/phpredis) and [Relay](https://relay.so/) into your Symfony application.

## Installation ##

@@ -52,7 +52,7 @@ You have to configure at least one client. In the above example your service
container will contain the service `snc_redis.default` which will return a
`Predis` client.

Available types are `predis` and `phpredis`.
Available types are `predis`, `phpredis` and `relay`.

A more complex setup which contains a clustered client could look like this:

@@ -69,7 +69,6 @@ snc_redis:
alias: cache
dsn: redis://secret@localhost/1
options:
profile: 2.2
connection_timeout: 10
read_write_timeout: 30
cluster:
@@ -105,13 +104,13 @@ snc_redis:
Please note that the master dsn connection needs to be tagged with the ```master``` alias.
If not, `predis` will complain.

A setup using `predis` or `phpredis` sentinel replication could look like this:
A setup using `predis`, `phpredis` or `relay` sentinel replication could look like this:

``` yaml
snc_redis:
clients:
default:
type: predis
type: "predis" # or "phpredis", or "relay"
alias: default
dsn:
- redis://localhost:26379
@@ -256,12 +255,6 @@ framework:
provider: snc_redis.cache
```

### Profiler storage ###

:warning: this feature is not supported anymore since Symfony 4.4 and will be automatically disabled if you are using Symfony 4.4.

>As the profiler must only be used on non-production servers, the file storage is more than enough and no other implementations will ever be supported.

### Complete configuration example ###

``` yaml
@@ -287,7 +280,6 @@ snc_redis:
- redis://pw@127.0.0.1:63790/10
options:
prefix: foo
profile: 2.4
connection_timeout: 10
connection_persistent: true
read_write_timeout: 30
1 change: 0 additions & 1 deletion src/DependencyInjection/Compiler/LoggingPass.php
Original file line number Diff line number Diff line change
@@ -44,7 +44,6 @@ public function process(ContainerBuilder $container): void

$connectionFactoryId = sprintf('snc_redis.%s_connectionfactory', $clientAlias);
$connectionFactoryDef = new Definition((string) $container->getParameter('snc_redis.connection_factory.class'));
$connectionFactoryDef->addArgument(new Reference(sprintf('snc_redis.client.%s_profile', $clientAlias)));
if ($container->getParameter('kernel.debug')) {
$connectionFactoryDef->addMethodCall('setStopwatch', [new Reference('debug.stopwatch', ContainerInterface::NULL_ON_INVALID_REFERENCE)]);
}
3 changes: 2 additions & 1 deletion src/DependencyInjection/Configuration/Configuration.php
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@
use Predis\Connection\Parameters;
use Redis;
use RedisCluster;
use Relay\Relay;
use Snc\RedisBundle\Client\Predis\Connection\ConnectionFactory;
use Snc\RedisBundle\Client\Predis\Connection\ConnectionWrapper;
use Snc\RedisBundle\DataCollector\RedisDataCollector;
@@ -54,6 +55,7 @@ public function getConfigTreeBuilder(): TreeBuilder
->scalarNode('connection_factory')->defaultValue(ConnectionFactory::class)->end()
->scalarNode('connection_wrapper')->defaultValue(ConnectionWrapper::class)->end()
->scalarNode('phpredis_client')->defaultValue(Redis::class)->end()
->scalarNode('relay_client')->defaultValue(Relay::class)->end()
->scalarNode('phpredis_clusterclient')->defaultValue(RedisCluster::class)->end()
->scalarNode('logger')->defaultValue(RedisLogger::class)->end()
->scalarNode('data_collector')->defaultValue(RedisDataCollector::class)->end()
@@ -123,7 +125,6 @@ private function addClientsSection(ArrayNodeDefinition $rootNode): void
->booleanNode('iterable_multibulk')->defaultFalse()->end()
->booleanNode('throw_errors')->defaultTrue()->end()
->scalarNode('serialization')->defaultValue('default')->end()
->scalarNode('profile')->defaultValue('default')->end()
->scalarNode('cluster')->defaultNull()->end()
->scalarNode('prefix')->defaultNull()->end()
->enumNode('replication')->values([true, 'sentinel'])->end()
26 changes: 4 additions & 22 deletions src/DependencyInjection/SncRedisExtension.php
Original file line number Diff line number Diff line change
@@ -15,8 +15,6 @@

use InvalidArgumentException;
use LogicException;
use Predis\Command\Processor\KeyPrefixProcessor;
use Predis\Profile\Factory;
use RedisSentinel;
use Snc\RedisBundle\DependencyInjection\Configuration\Configuration;
use Snc\RedisBundle\DependencyInjection\Configuration\RedisDsn;
@@ -37,8 +35,6 @@
use function assert;
use function class_exists;
use function count;
use function get_class;
use function is_string;
use function sprintf;

class SncRedisExtension extends Extension
@@ -119,6 +115,7 @@ private function loadClient(array $client, ContainerBuilder $container): void
$this->loadPredisClient($client, $container);
break;
case 'phpredis':
case 'relay':
$this->loadPhpredisClient($client, $container);
break;
default:
@@ -167,23 +164,6 @@ private function loadPredisClient(array $client, ContainerBuilder $container): v
$this->loadPredisConnectionParameters($client['alias'], $connection, $container, $dsn);
}

$profile = $client['options']['profile'];
// TODO can be shared between clients?!
$profile = $container->resolveEnvPlaceholders($profile, true);
$profile = !is_string($profile) ? sprintf('%.1F', $profile) : $profile;
$profileId = sprintf('snc_redis.client.%s_profile', $client['alias']);
$profileDef = new Definition(get_class(Factory::get($profile))); // TODO get_class alternative?
if ($client['options']['prefix'] !== null) {
$processorId = sprintf('snc_redis.client.%s_processor', $client['alias']);
$processorDef = new Definition(KeyPrefixProcessor::class);
$processorDef->setArguments([$client['options']['prefix']]);
$container->setDefinition($processorId, $processorDef);
$profileDef->addMethodCall('setProcessor', [new Reference($processorId)]);
}

$container->setDefinition($profileId, $profileDef);
$client['options']['profile'] = new Reference($profileId);

$optionId = sprintf('snc_redis.client.%s_options', $client['alias']);
$optionDef = new Definition((string) $container->getParameter('snc_redis.client_options.class'));
$optionDef->addArgument($client['options']);
@@ -238,7 +218,9 @@ private function loadPhpredisClient(array $options, ContainerBuilder $container)
throw new LogicException('You cannot have both cluster and sentinel enabled for same redis connection');
}

$phpredisClientClass = (string) $container->getParameter('snc_redis.phpredis_' . ($hasClusterOption ? 'cluster' : '') . 'client.class');
$phpredisClientClass = (string) $container->getParameter(
sprintf('snc_redis.%s_%sclient.class', $options['type'], ($hasClusterOption ? 'cluster' : '')),
);

$phpredisDef = new Definition($phpredisClientClass, [
$hasSentinelOption ? RedisSentinel::class : $phpredisClientClass,
66 changes: 36 additions & 30 deletions src/Factory/PhpredisClientFactory.php
Original file line number Diff line number Diff line change
@@ -14,14 +14,16 @@
use RedisSentinel;
use ReflectionClass;
use ReflectionMethod;
use Relay\Relay;
use Relay\Sentinel;
use Snc\RedisBundle\DependencyInjection\Configuration\RedisDsn;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;

use function array_key_exists;
use function array_keys;
use function array_map;
use function count;
use function defined;
use function get_class;
use function implode;
use function in_array;
use function is_a;
@@ -63,27 +65,28 @@ public function __construct(callable $interceptor, ?Configuration $proxyConfigur
* @param list<string|list<string>> $dsns Multiple DSN string
* @param mixed[] $options Options provided in bundle client config
*
* @return Redis|RedisCluster
* @return Redis|RedisCluster|Relay
*
* @throws InvalidConfigurationException
* @throws LogicException
*/
public function create(string $class, array $dsns, array $options, string $alias, bool $loggingEnabled)
{
$isRedis = is_a($class, Redis::class, true);
$isSentinel = is_a($class, RedisSentinel::class, true);
$isRelay = is_a($class, Relay::class, true);
$isSentinel = is_a($class, RedisSentinel::class, true) || is_a($class, Sentinel::class, true);
$isCluster = is_a($class, RedisCluster::class, true);

if (!$isRedis && !$isSentinel && !$isCluster) {
throw new LogicException(sprintf('The factory can only instantiate Redis|RedisCluster|RedisSentinel classes: "%s" asked', $class));
if (!$isRedis && !$isRelay && !$isSentinel && !$isCluster) {
throw new LogicException(sprintf('The factory can only instantiate Redis|Relay\Relay|RedisCluster|RedisSentinel|Relay\Sentinel classes: "%s" asked', $class));
}

// Normalize the DSNs, because using processed environment variables could lead to nested values.
$dsns = count($dsns) === 1 && is_array($dsns[0]) ? $dsns[0] : $dsns;

$parsedDsns = array_map(static fn (string $dsn) => new RedisDsn($dsn), $dsns);

if ($isRedis) {
if ($isRedis || $isRelay) {
if (count($parsedDsns) > 1) {
throw new LogicException('Cannot have more than 1 dsn with \Redis and \RedisArray is not supported yet.');
}
@@ -92,20 +95,26 @@ public function create(string $class, array $dsns, array $options, string $alias
}

if ($isSentinel) {
return $this->createClientFromSentinel($parsedDsns, $alias, $options, $loggingEnabled);
return $this->createClientFromSentinel($class, $parsedDsns, $alias, $options, $loggingEnabled);
}

return $this->createClusterClient($parsedDsns, $class, $alias, $options, $loggingEnabled);
}

/**
* @param class-string $class
* @param list<RedisDsn> $dsns
* @param array{service: ?string} $options
*
* @return Redis|Relay
*/
private function createClientFromSentinel(array $dsns, string $alias, array $options, bool $loggingEnabled): Redis
private function createClientFromSentinel(string $class, array $dsns, string $alias, array $options, bool $loggingEnabled)
{
$isRelay = is_a($class, Sentinel::class, true);
$sentinelClass = $isRelay ? Sentinel::class : RedisSentinel::class;

foreach ($dsns as $dsn) {
$address = (new RedisSentinel($dsn->getHost(), (int) $dsn->getPort()))->getMasterAddrByName($options['service']);
$address = (new $sentinelClass($dsn->getHost(), (int) $dsn->getPort()))->getMasterAddrByName($options['service']);

if (!$address) {
continue;
@@ -120,7 +129,7 @@ public function __construct(string $dsn, string $host, int $port)
$this->port = $port;
}
},
Redis::class,
$isRelay ? Relay::class : Redis::class,
$alias,
$options,
$loggingEnabled,
@@ -155,7 +164,7 @@ private function createClusterClient(array $dsns, string $class, string $alias,
);

if (isset($options['prefix'])) {
$client->setOption(Redis::OPT_PREFIX, $options['prefix']);
$client->setOption(2, $options['prefix']);
}

if (isset($options['serialization'])) {
@@ -169,8 +178,12 @@ private function createClusterClient(array $dsns, string $class, string $alias,
return $loggingEnabled ? $this->createLoggingProxy($client, $alias) : $client;
}

/** @param mixed[] $options */
private function createClient(RedisDsn $dsn, string $class, string $alias, array $options, bool $loggingEnabled): Redis
/**
* @param mixed[] $options
*
* @return Redis|Relay
*/
private function createClient(RedisDsn $dsn, string $class, string $alias, array $options, bool $loggingEnabled)
{
$client = new $class();

@@ -229,24 +242,18 @@ private function createClient(RedisDsn $dsn, string $class, string $alias, array
return $client;
}

/**
* @return Redis::SERIALIZER_*
*
* @throws InvalidConfigurationException
*/
/** @throws InvalidConfigurationException */
private function loadSerializationType(string $type): int
{
$types = [
'default' => Redis::SERIALIZER_NONE,
'json' => Redis::SERIALIZER_JSON,
'none' => Redis::SERIALIZER_NONE,
'php' => Redis::SERIALIZER_PHP,
'default' => 0, // Redis::SERIALIZER_NONE,
'none' => 0, // Redis::SERIALIZER_NONE,
'php' => 1, //Redis::SERIALIZER_PHP,
'igbinary' => 2, //Redis::SERIALIZER_IGBINARY,
'msgpack' => 3, //Redis::SERIALIZER_MSGPACK,
'json' => 4, // Redis::SERIALIZER_JSON,
];

if (defined('Redis::SERIALIZER_IGBINARY')) {
$types['igbinary'] = Redis::SERIALIZER_IGBINARY;
}

if (array_key_exists($type, $types)) {
return $types[$type];
}
@@ -275,14 +282,13 @@ private function loadSlaveFailoverType(string $type): int
*
* @return T
*
* @template T of Redis|RedisCluster
* @template T of Redis|Relay|RedisCluster
*/
private function createLoggingProxy(object $client, string $alias): object
{
$prefixInterceptors = [];
$classToCopyMethodsFrom = $client instanceof Redis ? Redis::class : RedisCluster::class;
$prefixInterceptors = [];

foreach ((new ReflectionClass($classToCopyMethodsFrom))->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
foreach ((new ReflectionClass(get_class($client)))->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
$name = $method->getName();

if ($name[0] === '_' || in_array($name, self::CLIENT_ONLY_COMMANDS, true)) {
3 changes: 2 additions & 1 deletion src/Factory/PredisParametersFactory.php
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@
use Predis\Connection\ParametersInterface;
use Snc\RedisBundle\DependencyInjection\Configuration\RedisDsn;

use function array_filter;
use function array_merge;
use function is_a;
use function sprintf;
@@ -62,6 +63,6 @@ private static function parseDsn(RedisDsn $dsn): array
$options['alias'] = $dsn->getAlias();
}

return $options;
return array_filter($options, static fn ($value) => $value !== null);
}
}
Loading