Skip to content

Commit

Permalink
Fix support for DSN env variable with phpredis (#432)
Browse files Browse the repository at this point in the history
  • Loading branch information
B-Galati authored and curry684 committed Jun 25, 2018
1 parent 6e5406a commit 9bb9dd6
Show file tree
Hide file tree
Showing 15 changed files with 355 additions and 172 deletions.
44 changes: 8 additions & 36 deletions DependencyInjection/Configuration/RedisDsn.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,11 @@ class RedisDsn
*/
protected $alias;

/**
* @var bool
*/
protected $isEnv;

/**
* @param string $dsn
* @param bool $isEnv
*/
public function __construct($dsn, $isEnv)
public function __construct($dsn)
{
$this->isEnv = $isEnv;
$this->dsn = $dsn;
$this->parseDsn($dsn);
}
Expand Down Expand Up @@ -137,33 +130,11 @@ public function getPersistentId()
return md5($this->dsn);
}

/**
* Return the env DSN if one exists, null otherwise
*
* @return string|null
*/
public function getEnvDsn()
{
return $this->isEnv() ? $this->dsn : null;
}

/**
* @return bool
*/
public function isEnv()
{
return $this->isEnv;
}

/**
* @return bool
*/
public function isValid()
{
if ($this->isEnv()) {
return true;
}

if (0 !== strpos($this->dsn, 'redis://')) {
return false;
}
Expand All @@ -184,10 +155,6 @@ public function isValid()
*/
protected function parseDsn($dsn)
{
if ($this->isEnv()) {
return;
}

$dsn = str_replace('redis://', '', $dsn); // remove "redis://"
if (false !== $pos = strrpos($dsn, '@')) {
// parse password
Expand All @@ -202,12 +169,12 @@ protected function parseDsn($dsn)
$dsn = substr($dsn, $pos + 1);
}
$dsn = preg_replace_callback('/\?(.*)$/', array($this, 'parseParameters'), $dsn); // parse parameters
if (preg_match('#^(.*)/(\d+|%[^%]+%|env_\w+_[[:xdigit:]]{32,})$#', $dsn, $matches)) {
if (preg_match('#^(.*)/(\d+|%[^%]+%)$#', $dsn, $matches)) {
// parse database
$this->database = is_numeric($matches[2]) ? (int) $matches[2] : $matches[2];
$dsn = $matches[1];
}
if (preg_match('#^([^:]+)(:(\d+|%[^%]+%|env_\w+_[[:xdigit:]]{32,}))?$#', $dsn, $matches)) {
if (preg_match('#^([^:]+)(:(\d+|%[^%]+%))?$#', $dsn, $matches)) {
if (!empty($matches[1])) {
// parse host/ip or socket
if ('/' === $matches[1]{0}) {
Expand Down Expand Up @@ -255,4 +222,9 @@ protected function parseParameters($matches)

return '';
}

public function __toString()
{
return $this->dsn;
}
}
27 changes: 27 additions & 0 deletions DependencyInjection/Configuration/RedisEnvDsn.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

/*
* This file is part of the SncRedisBundle package.
*
* (c) Henrik Westphal <henrik.westphal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Snc\RedisBundle\DependencyInjection\Configuration;

class RedisEnvDsn
{
private $dsn;

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

public function __toString()
{
return $this->dsn;
}
}
108 changes: 30 additions & 78 deletions DependencyInjection/SncRedisExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

use Snc\RedisBundle\DependencyInjection\Configuration\Configuration;
use Snc\RedisBundle\DependencyInjection\Configuration\RedisDsn;
use Snc\RedisBundle\DependencyInjection\Configuration\RedisEnvDsn;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
Expand Down Expand Up @@ -101,7 +103,11 @@ protected function loadClient(array $client, ContainerBuilder $container)
$container->resolveEnvPlaceholders($dsn, null, $usedEnvs);
}

$parsedDsn = new RedisDsn($dsn, !empty($usedEnvs));
if ($usedEnvs) {
return new RedisEnvDsn($dsn);
}

$parsedDsn = new RedisDsn($dsn);

if ($parsedDsn->isValid()) {
return $parsedDsn;
Expand Down Expand Up @@ -151,7 +157,8 @@ protected function loadPredisClient(array $client, ContainerBuilder $container)

/** @var RedisDsn $dsn */
foreach ($client['dsns'] as $i => $dsn) {
if (!$connectionAlias = $dsn->getAlias()) {
$connectionAlias = $dsn instanceof RedisDsn ? $dsn->getAlias() : null;
if (!$connectionAlias) {
$connectionAlias = 1 === $connectionCount ? $client['alias'] : $client['alias'] . ($i + 1);
}
$connectionAliases[] = $connectionAlias;
Expand All @@ -160,7 +167,7 @@ protected function loadPredisClient(array $client, ContainerBuilder $container)
$connection['logging'] = $client['logging'];
$connection['alias'] = $connectionAlias;

if (!$dsn->isEnv()) {
if ($dsn instanceof RedisDsn) {
if (null !== $dsn->getSocket()) {
$connection['scheme'] = 'unix';
$connection['path'] = $dsn->getSocket();
Expand Down Expand Up @@ -226,12 +233,12 @@ protected function loadPredisClient(array $client, ContainerBuilder $container)
/**
* Loads a connection.
*
* @param string $clientAlias The client alias
* @param array $connection A connection configuration
* @param ContainerBuilder $container A ContainerBuilder instance
* @param string|null $envDsn Env DSN
* @param string $clientAlias The client alias
* @param array $connection A connection configuration
* @param ContainerBuilder $container A ContainerBuilder instance
* @param RedisEnvDsn|RedisDsn $dsn DSN object
*/
protected function loadPredisConnectionParameters($clientAlias, array $connection, ContainerBuilder $container, RedisDsn $dsn)
protected function loadPredisConnectionParameters($clientAlias, array $connection, ContainerBuilder $container, $dsn)
{
$parametersClass = $container->getParameter('snc_redis.connection_parameters.class');

Expand All @@ -240,10 +247,10 @@ protected function loadPredisConnectionParameters($clientAlias, array $connectio
$parameterDef->setPublic(false);
$parameterDef->addArgument($connection);

if ($dsn->isEnv()) {
$parameterDef->setFactory(array('Snc\RedisBundle\Factory\EnvParametersFactory', 'create'));
if ($dsn instanceof RedisEnvDsn) {
$parameterDef->setFactory(array('Snc\RedisBundle\Factory\PredisEnvParametersFactory', 'create'));
$parameterDef->addArgument($parametersClass);
$parameterDef->addArgument($dsn->getEnvDsn());
$parameterDef->addArgument((string) $dsn);
}

$parameterDef->addTag('snc_redis.connection_parameters', array('clientAlias' => $clientAlias));
Expand Down Expand Up @@ -276,52 +283,24 @@ protected function loadPhpredisClient(array $client, ContainerBuilder $container
@trigger_error(sprintf('Redis logging is not supported on PhpRedis %s and has been automatically disabled, disable logging in config to suppress this warning', $phpRedisVersion), E_USER_WARNING);
}

$phpredisDef = new Definition($container->getParameter('snc_redis.phpredis_client.class'));
$phpredisClientclass = $container->getParameter('snc_redis.phpredis_client.class');
if ($client['logging']) {
$phpredisDef = new Definition($container->getParameter('snc_redis.phpredis_connection_wrapper.class'));
$phpredisDef->addArgument(array('alias' => $client['alias']));
$phpredisDef->addArgument(new Reference('snc_redis.logger'));
$phpredisClientclass = $container->getParameter('snc_redis.phpredis_connection_wrapper.class');
}

$phpredisDef = new Definition($phpredisClientclass);
$phpredisDef->setFactory(array(
new Definition('Snc\RedisBundle\Factory\PhpredisClientFactory', array(new Reference('snc_redis.logger'))),
'create'
));
$phpredisDef->addArgument($phpredisClientclass);
$phpredisDef->addArgument((string) $dsn);
$phpredisDef->addArgument($client['options']);
$phpredisDef->addArgument($client['alias']);
$phpredisDef->addTag('snc_redis.client', array('alias' => $client['alias']));
$phpredisDef->setPublic(false);
$connectMethod = $client['options']['connection_persistent'] ? 'pconnect' : 'connect';
$connectParameters = array();
if (null !== $dsn->getSocket()) {
$connectParameters[] = $dsn->getSocket();
$connectParameters[] = null;
} else {
$connectParameters[] = $dsn->getHost();
$connectParameters[] = $dsn->getPort();
}
if ($client['options']['connection_timeout']) {
$connectParameters[] = $client['options']['connection_timeout'];
} else {
$connectParameters[] = null;
}
if ($client['options']['connection_persistent']) {
$connectParameters[] = $dsn->getPersistentId();
}

$phpredisDef->addMethodCall($connectMethod, $connectParameters);
if ($client['options']['prefix']) {
$phpredisDef->addMethodCall('setOption', array(\Redis::OPT_PREFIX, $client['options']['prefix']));
}
if (null !== $dsn->getPassword()) {
$phpredisDef->addMethodCall('auth', array($dsn->getPassword()));
}
if (null !== $dsn->getDatabase()) {
$phpredisDef->addMethodCall('select', array($dsn->getDatabase()));
}
if ($client['options']['serialization']) {
$phpredisDef->addMethodCall(
'setOption',
array(\Redis::OPT_SERIALIZER, $this->loadSerializationType($client['options']['serialization']))
);
}
$container->setDefinition($phpredisId, $phpredisDef);

$container->setAlias(sprintf('snc_redis.%s', $client['alias']), $phpredisId);
$container->setAlias(sprintf('snc_redis.%s', $client['alias']), new Alias($phpredisId, true));
$container->setAlias(sprintf('snc_redis.%s_client', $client['alias']), $phpredisId);
}

Expand Down Expand Up @@ -445,33 +424,6 @@ protected function loadSwiftMailer(array $config, ContainerBuilder $container)
$container->setAlias('swiftmailer.spool.redis', 'snc_redis.swiftmailer.spool');
}

/**
* Load the correct serializer for Redis
*
* @param string $type
*
* @return string
* @throws InvalidConfigurationException
*/
public function loadSerializationType($type)
{
$types = array(
'default' => \Redis::SERIALIZER_NONE,
'none' => \Redis::SERIALIZER_NONE,
'php' => \Redis::SERIALIZER_PHP
);

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

if (array_key_exists($type, $types)) {
return $types[$type];
}

throw new InvalidConfigurationException(sprintf('%s in not a valid serializer. Valid serializers: %s', $type, implode(", ", array_keys($types))));
}

/* Loads the profiler storage configuration.
*
* @param array $config A configuration array
Expand Down
Loading

0 comments on commit 9bb9dd6

Please sign in to comment.