diff --git a/bin/dev b/bin/dev index 46bf47995..6858769ee 100755 --- a/bin/dev +++ b/bin/dev @@ -6,13 +6,13 @@ set -e while getopts "bustefcdp" OPTION; do case $OPTION in b) - COMPOSE_PROJECT_NAME=mqdev docker-compose pull && COMPOSE_PROJECT_NAME=mqdev docker-compose build + docker-compose pull && docker-compose build ;; u) - COMPOSE_PROJECT_NAME=mqdev docker-compose up + docker-compose up ;; s) - COMPOSE_PROJECT_NAME=mqdev docker-compose stop + docker-compose stop ;; e) docker exec -it mqdev_dev_1 /bin/bash @@ -24,10 +24,10 @@ while getopts "bustefcdp" OPTION; do ./bin/run-fun-test.sh "$2" ;; c) - COMPOSE_PROJECT_NAME=mqdev docker-compose run -e CHANGELOG_GITHUB_TOKEN=${CHANGELOG_GITHUB_TOKEN:-""} --workdir="/mqdev" --rm generate-changelog github_changelog_generator --future-release "$2" --simple-list + docker-compose run -e CHANGELOG_GITHUB_TOKEN=${CHANGELOG_GITHUB_TOKEN:-""} --workdir="/mqdev" --rm generate-changelog github_changelog_generator --future-release "$2" --simple-list ;; - d) COMPOSE_PROJECT_NAME=mqdev docker-compose run --workdir="/mqdev" --rm dev php pkg/enqueue-bundle/Tests/Functional/app/console.php config:dump-reference enqueue -vvv + d) docker-compose run --workdir="/mqdev" --rm dev php pkg/enqueue-bundle/Tests/Functional/app/console.php config:dump-reference enqueue -vvv ;; \?) echo "Invalid option: -$OPTARG" >&2 diff --git a/docs/transport/redis.md b/docs/transport/redis.md index 0b362217a..3a1240bd8 100644 --- a/docs/transport/redis.md +++ b/docs/transport/redis.md @@ -78,6 +78,23 @@ $connectionFactory = new RedisConnectionFactory([ $psrContext = $connectionFactory->createContext(); ``` +* With custom redis instance: + +It gives you more control over vendor specific features. + +```php + 'custom', 'redis' => $redis]); +``` + ## Send message to topic ```php diff --git a/pkg/redis/RedisConnectionFactory.php b/pkg/redis/RedisConnectionFactory.php index 021a448f4..3ed90dc5d 100644 --- a/pkg/redis/RedisConnectionFactory.php +++ b/pkg/redis/RedisConnectionFactory.php @@ -25,6 +25,7 @@ class RedisConnectionFactory implements PsrConnectionFactory * 'reserved' => should be null if $retry_interval is specified * 'retry_interval' => retry interval in milliseconds. * 'vendor' => 'The library used internally to interact with Redis server + * 'redis' => 'Used only if vendor is custom, should contain an instance of \Enqueue\Redis\Redis interface. * 'persisted' => bool, Whether it use single persisted connection or open a new one for every context * 'lazy' => the connection will be performed as later as possible, if the option set to true * 'database' => Database index to select when connected (default value: 0) @@ -50,7 +51,7 @@ public function __construct($config = 'redis:') $this->config = array_replace($this->defaultConfig(), $config); - $supportedVendors = ['predis', 'phpredis']; + $supportedVendors = ['predis', 'phpredis', 'custom']; if (false == in_array($this->config['vendor'], $supportedVendors, true)) { throw new \LogicException(sprintf( 'Unsupported redis vendor given. It must be either "%s". Got "%s"', @@ -90,6 +91,18 @@ private function createRedis() $this->redis = new PRedis(new Client($this->config, ['exceptions' => true])); } + if ('custom' == $this->config['vendor'] && false == $this->redis) { + if (empty($this->config['redis'])) { + throw new \LogicException('The redis option should be set if vendor is custom.'); + } + + if (false == $this->config['redis'] instanceof Redis) { + throw new \LogicException(sprintf('The redis option should be instance of "%s".', Redis::class)); + } + + $this->redis = $this->config['redis']; + } + $this->redis->connect(); } @@ -138,6 +151,7 @@ private function defaultConfig() 'reserved' => null, 'retry_interval' => null, 'vendor' => 'phpredis', + 'redis' => null, 'persisted' => false, 'lazy' => true, 'database' => 0, diff --git a/pkg/redis/Symfony/RedisTransportFactory.php b/pkg/redis/Symfony/RedisTransportFactory.php index 5fcbe7603..a4187ac9d 100644 --- a/pkg/redis/Symfony/RedisTransportFactory.php +++ b/pkg/redis/Symfony/RedisTransportFactory.php @@ -49,10 +49,14 @@ public function addConfiguration(ArrayNodeDefinition $builder) ->end() ->integerNode('port')->end() ->enumNode('vendor') - ->values(['phpredis', 'predis']) + ->values(['phpredis', 'predis', 'custom']) ->cannotBeEmpty() ->info('The library used internally to interact with Redis server') ->end() + ->scalarNode('redis') + ->cannotBeEmpty() + ->info('A custom redis service id, used with vendor true only') + ->end() ->booleanNode('persisted') ->defaultFalse() ->info('bool, Whether it use single persisted connection or open a new one for every context') @@ -73,6 +77,10 @@ public function addConfiguration(ArrayNodeDefinition $builder) */ public function createConnectionFactory(ContainerBuilder $container, array $config) { + if (false == empty($config['redis'])) { + $config['redis'] = new Reference($config['redis']); + } + $factory = new Definition(RedisConnectionFactory::class); $factory->setArguments([isset($config['dsn']) ? $config['dsn'] : $config]); diff --git a/pkg/redis/Tests/RedisConnectionFactoryConfigTest.php b/pkg/redis/Tests/RedisConnectionFactoryConfigTest.php index 06309824f..cfcdf959b 100644 --- a/pkg/redis/Tests/RedisConnectionFactoryConfigTest.php +++ b/pkg/redis/Tests/RedisConnectionFactoryConfigTest.php @@ -40,7 +40,7 @@ public function testThrowIfDsnCouldNotBeParsed() public function testThrowIfVendorIsInvalid() { $this->expectException(\LogicException::class); - $this->expectExceptionMessage('Unsupported redis vendor given. It must be either "predis", "phpredis". Got "invalidVendor"'); + $this->expectExceptionMessage('Unsupported redis vendor given. It must be either "predis", "phpredis", "custom". Got "invalidVendor"'); new RedisConnectionFactory(['vendor' => 'invalidVendor']); } @@ -72,6 +72,7 @@ public static function provideConfigs() 'persisted' => false, 'lazy' => true, 'database' => 0, + 'redis' => null, ], ]; @@ -87,6 +88,7 @@ public static function provideConfigs() 'persisted' => false, 'lazy' => true, 'database' => 0, + 'redis' => null, ], ]; @@ -102,6 +104,7 @@ public static function provideConfigs() 'persisted' => false, 'lazy' => true, 'database' => 0, + 'redis' => null, ], ]; @@ -118,6 +121,7 @@ public static function provideConfigs() 'lazy' => false, 'foo' => 'bar', 'database' => 5, + 'redis' => null, ], ]; @@ -134,6 +138,7 @@ public static function provideConfigs() 'lazy' => true, 'foo' => 'bar', 'database' => 0, + 'redis' => null, ], ]; } diff --git a/pkg/redis/Tests/RedisConnectionFactoryTest.php b/pkg/redis/Tests/RedisConnectionFactoryTest.php index b5d7347ab..e6d740836 100644 --- a/pkg/redis/Tests/RedisConnectionFactoryTest.php +++ b/pkg/redis/Tests/RedisConnectionFactoryTest.php @@ -2,6 +2,7 @@ namespace Enqueue\Redis\Tests; +use Enqueue\Redis\Redis; use Enqueue\Redis\RedisConnectionFactory; use Enqueue\Redis\RedisContext; use Enqueue\Test\ClassExtensionTrait; @@ -28,4 +29,45 @@ public function testShouldCreateLazyContext() $this->assertAttributeEquals(null, 'redis', $context); $this->assertInternalType('callable', $this->readAttribute($context, 'redisFactory')); } + + public function testShouldThrowIfVendorIsCustomButRedisInstanceNotSet() + { + $factory = new RedisConnectionFactory([ + 'vendor' => 'custom', + 'redis' => null, + 'lazy' => false, + ]); + + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('The redis option should be set if vendor is custom.'); + $factory->createContext(); + } + + public function testShouldThrowIfVendorIsCustomButRedisIsNotInstanceOfRedis() + { + $factory = new RedisConnectionFactory([ + 'vendor' => 'custom', + 'redis' => new \stdClass(), + 'lazy' => false, + ]); + + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('The redis option should be instance of "Enqueue\Redis\Redis".'); + $factory->createContext(); + } + + public function testShouldUseCustomRedisInstance() + { + $redisMock = $this->createMock(Redis::class); + + $factory = new RedisConnectionFactory([ + 'vendor' => 'custom', + 'redis' => $redisMock, + 'lazy' => false, + ]); + + $context = $factory->createContext(); + + $this->assertAttributeSame($redisMock, 'redis', $context); + } } diff --git a/pkg/redis/Tests/Symfony/RedisTransportFactoryTest.php b/pkg/redis/Tests/Symfony/RedisTransportFactoryTest.php index 3a1512d84..04a6b70da 100644 --- a/pkg/redis/Tests/Symfony/RedisTransportFactoryTest.php +++ b/pkg/redis/Tests/Symfony/RedisTransportFactoryTest.php @@ -104,6 +104,35 @@ public function testShouldCreateConnectionFactory() ]], $factory->getArguments()); } + public function testShouldCreateConnectionFactoryWithCustomRedisInstance() + { + $container = new ContainerBuilder(); + + $transport = new RedisTransportFactory(); + + $serviceId = $transport->createConnectionFactory($container, [ + 'host' => 'localhost', + 'port' => 123, + 'vendor' => 'custom', + 'redis' => 'a.redis.service', + ]); + + $this->assertTrue($container->hasDefinition($serviceId)); + $factory = $container->getDefinition($serviceId); + $this->assertEquals(RedisConnectionFactory::class, $factory->getClass()); + + $config = $factory->getArgument(0); + + $this->assertInternalType('array', $config); + + $this->assertArrayHasKey('vendor', $config); + $this->assertSame('custom', $config['vendor']); + + $this->assertArrayHasKey('redis', $config); + $this->assertInstanceOf(Reference::class, $config['redis']); + $this->assertSame('a.redis.service', (string) $config['redis']); + } + public function testShouldCreateContext() { $container = new ContainerBuilder(); diff --git a/pkg/simple-client/SimpleClient.php b/pkg/simple-client/SimpleClient.php index 596793863..5f50396ff 100644 --- a/pkg/simple-client/SimpleClient.php +++ b/pkg/simple-client/SimpleClient.php @@ -26,14 +26,20 @@ use Interop\Queue\PsrContext; use Interop\Queue\PsrProcessor; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ContainerInterface; final class SimpleClient { /** - * @var ContainerBuilder + * @var ContainerInterface */ private $container; + /** + * @var array|string + */ + private $config; + /** * The config could be a transport DSN (string) or an array, here's an example of a few DSNs:. * @@ -73,11 +79,13 @@ final class SimpleClient * ] * * - * @param string|array $config + * @param string|array $config + * @param ContainerBuilder|null $container */ - public function __construct($config) + public function __construct($config, ContainerBuilder $container = null) { - $this->container = $this->buildContainer($config); + $this->container = $this->buildContainer($config, $container ?: new ContainerBuilder()); + $this->config = $config; } /** @@ -252,16 +260,16 @@ public function getRouterProcessor() } /** - * @param array|string $config + * @param array|string $config + * @param ContainerBuilder $container * - * @return ContainerBuilder + * @return ContainerInterface */ - private function buildContainer($config) + private function buildContainer($config, ContainerBuilder $container) { $config = $this->buildConfig($config); $extension = $this->buildContainerExtension(); - $container = new ContainerBuilder(); $container->registerExtension($extension); $container->loadFromExtension($extension->getAlias(), $config);