diff --git a/DependencyInjection/Compiler/ProviderCompilerPass.php b/DependencyInjection/Compiler/ProviderCompilerPass.php new file mode 100644 index 0000000..9115cb9 --- /dev/null +++ b/DependencyInjection/Compiler/ProviderCompilerPass.php @@ -0,0 +1,56 @@ +has('swarrot.factory.default') || !$container->hasParameter('swarrot.provider_config')) { + return; + } + + $providersIds = []; + + foreach ($container->findTaggedServiceIds('swarrot.provider_factory') as $id => $tags) { + foreach ($tags as $tag) { + if (!isset($tag['alias'])) { + throw new \InvalidArgumentException( + sprintf('The provider\'s alias is no defined for the service "%s"', $id) + ); + } + $providersIds[$tag['alias']] = $id; + } + } + + list($provider, $connections) = $container->getParameter('swarrot.provider_config'); + + if (!isset($providersIds[$provider])) { + throw new \InvalidArgumentException(sprintf('Invalid provider "%s"', $provider)); + } + + $id = $providersIds[$provider]; + $definition = $container->getDefinition($id); + $className = $container->getParameterBag()->resolveValue($definition->getClass()); + + $reflection = new \ReflectionClass($className); + + if (!$reflection->implementsInterface('Swarrot\\SwarrotBundle\\Broker\\FactoryInterface')) { + throw new \InvalidArgumentException(sprintf('The provider "%s" is not valid', $provider)); + } + + foreach ($connections as $name => $connectionConfig) { + $definition->addMethodCall('addConnection', [ + $name, + $connectionConfig + ]); + } + + $container->setAlias('swarrot.factory.default', $id); + $container->getParameterBag()->remove('swarrot.provider_config'); + } +} diff --git a/DependencyInjection/SwarrotExtension.php b/DependencyInjection/SwarrotExtension.php index 570bcda..4391e01 100644 --- a/DependencyInjection/SwarrotExtension.php +++ b/DependencyInjection/SwarrotExtension.php @@ -24,26 +24,12 @@ public function load(array $configs, ContainerBuilder $container) $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); $loader->load('swarrot.xml'); - $id = 'swarrot.factory.'.$config['provider']; - if (!$container->has($id)) { - throw new \InvalidArgumentException('Unsupported provider'); - } - - $definition = $container->getDefinition($id); - - foreach ($config['connections'] as $name => $connectionConfig) { - $definition->addMethodCall('addConnection', array( - $name, - $connectionConfig - )); - } - if (null === $config['default_connection']) { reset($config['connections']); $config['default_connection'] = key($config['connections']); } - $container->setAlias('swarrot.factory.default', $id); + $container->setParameter('swarrot.provider_config', [$config['provider'], $config['connections']]); $commands = array(); foreach ($config['consumers'] as $name => $consumerConfig) { diff --git a/README.md b/README.md index 51dbbc0..bc81e29 100755 --- a/README.md +++ b/README.md @@ -169,6 +169,38 @@ You can also use options of the commande line: Default values will be override by your `config.yml` and use of options will override defaut|config values. +## Implementing your own Provider +If you want to implement your own provider (like Redis). First, you have to implements the `Swarrot\SwarrotBundle\Broker\FactoryInterface`. +Then, you can register it with along the others services and tag it with `swarrot.provider_factory`. + +```yaml +services: + app.swarrot.custom_provider_factory: + class: AppBundle\Provider\CustomFactory + tags: + - {name: swarrot.provider_factory} + app.swarrot.redis_provider_factory: + class: AppBundle\Provider\RedisFactory + tags: + - {name: swarrot.provider_factory, alias: redis} +``` + +Now you can tell to swarrot to use it in the `config.yml` file. + +```yaml +swarrot: + provider: app.swarrot.custom_provider_factory + ... +``` + +or with the alias + +```yaml +swarrot: + provider: redis + ... +``` + ## Running your tests without publishing If you use Swarrot you may not want to realy publish messages like in test environment for example. You can use the `BlackholePublisher` to achieve this. diff --git a/Resources/config/swarrot.xml b/Resources/config/swarrot.xml index 248378c..ff5ba2b 100644 --- a/Resources/config/swarrot.xml +++ b/Resources/config/swarrot.xml @@ -10,8 +10,12 @@ - - + + + + + + diff --git a/SwarrotBundle.php b/SwarrotBundle.php index 39049dd..eae5528 100644 --- a/SwarrotBundle.php +++ b/SwarrotBundle.php @@ -2,11 +2,20 @@ namespace Swarrot\SwarrotBundle; -use Symfony\Component\HttpKernel\Bundle\Bundle; +use Swarrot\SwarrotBundle\DependencyInjection\Compiler\ProviderCompilerPass; use Symfony\Component\Console\Application; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\HttpKernel\Bundle\Bundle; class SwarrotBundle extends Bundle { + public function build(ContainerBuilder $container) + { + parent::build($container); + + $container->addCompilerPass(new ProviderCompilerPass()); + } + public function registerCommands(Application $application) { $container = $application->getKernel()->getContainer(); diff --git a/Tests/DependencyInjection/Compiler/ProviderCompilerPassTest.php b/Tests/DependencyInjection/Compiler/ProviderCompilerPassTest.php new file mode 100644 index 0000000..a79ec3a --- /dev/null +++ b/Tests/DependencyInjection/Compiler/ProviderCompilerPassTest.php @@ -0,0 +1,330 @@ +assertInstanceOf( + 'Swarrot\\SwarrotBundle\\DependencyInjection\\Compiler\\ProviderCompilerPass', + new ProviderCompilerPass() + ); + } + + public function test_should_not_run_if_already_declared() + { + $container = $this->getContainer(); + + $container + ->expects($this->once()) + ->method('has') + ->with('swarrot.factory.default') + ->willReturn(true) + ; + + $container->expects($this->never())->method('setAlias'); + $container->expects($this->never())->method('hasParameter'); + $container->expects($this->never())->method('getParameter'); + $container->expects($this->never())->method('getDefinition'); + $container->expects($this->never())->method('findTaggedServiceIds'); + + $compiler = new ProviderCompilerPass; + $compiler->process($container); + } + + public function test_should_not_run_if_not_configured() + { + $container = $this->getContainer(); + + $container + ->expects($this->once()) + ->method('has') + ->with('swarrot.factory.default') + ->willReturn(false) + ; + $container + ->expects($this->once()) + ->method('hasParameter') + ->with('swarrot.provider_config') + ->willReturn(false) + ; + + $container->expects($this->never())->method('setAlias'); + $container->expects($this->never())->method('getParameter'); + $container->expects($this->never())->method('getDefinition'); + $container->expects($this->never())->method('findTaggedServiceIds'); + + $compiler = new ProviderCompilerPass; + $compiler->process($container); + } + + /** + * @expectedException InvalidArgumentException + * @expectedExceptionMessage The provider's alias is no defined for the service "foo" + */ + public function test_missing_alias() + { + $container = $this->getContainer(); + + $container + ->expects($this->once()) + ->method('has') + ->with('swarrot.factory.default') + ->willReturn(false) + ; + $container + ->expects($this->once()) + ->method('hasParameter') + ->with('swarrot.provider_config') + ->willReturn(true) + ; + $container + ->expects($this->once()) + ->method('findTaggedServiceIds') + ->with('swarrot.provider_factory') + ->willReturn([ + 'foo' => [ + [] + ] + ]) + ; + + $container->expects($this->never())->method('getParameter'); + $container->expects($this->never())->method('setAlias'); + $container->expects($this->never())->method('getDefinition'); + + $compiler = new ProviderCompilerPass; + $compiler->process($container); + } + + /** + * @expectedException InvalidArgumentException + * @expectedExceptionMessage Invalid provider "foo" + */ + public function test_unexistant_provider() + { + $container = $this->getContainer(); + + $container + ->expects($this->once()) + ->method('has') + ->with('swarrot.factory.default') + ->willReturn(false) + ; + $container + ->expects($this->once()) + ->method('hasParameter') + ->with('swarrot.provider_config') + ->willReturn(true) + ; + $container + ->expects($this->once()) + ->method('findTaggedServiceIds') + ->with('swarrot.provider_factory') + ->willReturn([ + 'foo' => [ + [ + 'alias' => 'foo.bar' + ] + ], + 'bar' => [ + [ + 'alias' => 'bar' + ] + ] + ]) + ; + $container + ->expects($this->once()) + ->method('getParameter') + ->with('swarrot.provider_config') + ->willReturn([ + 'foo', + [] + ]) + ; + + $container->expects($this->never())->method('setAlias'); + $container->expects($this->never())->method('getDefinition'); + + $compiler = new ProviderCompilerPass; + $compiler->process($container); + } + + /** + * @expectedException InvalidArgumentException + * @expectedExceptionMessage The provider "foo.bar" is not valid + */ + public function test_invalid_provider() + { + $container = $this->getContainer(); + $definition = $this->getMock('Symfony\\Component\\DependencyInjection\\Definition'); + + $definition->expects($this->once()) + ->method('getClass') + ->with() + ->willReturn('stdClass') + ; + $definition->expects($this->never())->method('addMethodCall'); + + $container->getParameterBag() + ->expects($this->once()) + ->method('resolveValue') + ->with('stdClass') + ->willReturn('stdClass') + ; + + $container + ->expects($this->once()) + ->method('has') + ->with('swarrot.factory.default') + ->willReturn(false) + ; + $container + ->expects($this->once()) + ->method('hasParameter') + ->with('swarrot.provider_config') + ->willReturn(true) + ; + $container + ->expects($this->once()) + ->method('findTaggedServiceIds') + ->with('swarrot.provider_factory') + ->willReturn([ + 'foo' => [ + [ + 'alias' => 'foo.bar' + ] + ], + 'bar' => [ + [ + 'alias' => 'bar' + ] + ] + ]) + ; + $container + ->expects($this->once()) + ->method('getParameter') + ->with('swarrot.provider_config') + ->willReturn([ + 'foo.bar', + [] + ]) + ; + $container + ->expects($this->once()) + ->method('getDefinition') + ->with('foo') + ->willReturn($definition) + ; + + $container->expects($this->never())->method('setAlias'); + + $compiler = new ProviderCompilerPass; + $compiler->process($container); + } + + public function test_successful_provider() + { + $container = $this->getContainer(); + $definition = $this->getMock('Symfony\\Component\\DependencyInjection\\Definition'); + + $definition->expects($this->once()) + ->method('getClass') + ->with() + ->willReturn('Swarrot\\SwarrotBundle\\Broker\\FactoryInterface') + ; + $definition->expects($this->once()) + ->method('addMethodCall') + ->with('addConnection', ['foo', []]) + ; + + $container->getParameterBag() + ->expects($this->once()) + ->method('resolveValue') + ->with('Swarrot\\SwarrotBundle\\Broker\\FactoryInterface') + ->willReturn('Swarrot\\SwarrotBundle\\Broker\\FactoryInterface') + ; + + $container + ->expects($this->once()) + ->method('has') + ->with('swarrot.factory.default') + ->willReturn(false) + ; + $container + ->expects($this->once()) + ->method('hasParameter') + ->with('swarrot.provider_config') + ->willReturn(true) + ; + $container + ->expects($this->once()) + ->method('findTaggedServiceIds') + ->with('swarrot.provider_factory') + ->willReturn([ + 'foo' => [ + [ + 'alias' => 'foo.bar' + ] + ], + 'bar' => [ + [ + 'alias' => 'bar' + ] + ] + ]) + ; + $container + ->expects($this->once()) + ->method('getParameter') + ->with('swarrot.provider_config') + ->willReturn([ + 'foo.bar', + [ + 'foo' => [] + ] + ]) + ; + $container + ->expects($this->once()) + ->method('getDefinition') + ->with('foo') + ->willReturn($definition) + ; + $container + ->expects($this->once()) + ->method('setAlias') + ->with('swarrot.factory.default', 'foo') + ; + + $compiler = new ProviderCompilerPass; + $compiler->process($container);; + } + + private function getContainer() + { + $container = $this->getMock('Symfony\\Component\\DependencyInjection\\ContainerBuilder', [ + 'has', + 'setAlias', + 'hasParameter', + 'getParameter', + 'getDefinition', + 'getParameterBag', + 'findTaggedServiceIds', + ]); + $parameterBag = $this->getMock('Symfony\\Component\\DependencyInjection\\ParameterBag\\ParameterBag'); + + $container + ->expects($this->any()) + ->method('getParameterBag') + ->willReturn($parameterBag) + ; + + return $container; + } +} diff --git a/Tests/DependencyInjection/SwarrotExtensionTest.php b/Tests/DependencyInjection/SwarrotExtensionTest.php index a19ecdd..89cb702 100644 --- a/Tests/DependencyInjection/SwarrotExtensionTest.php +++ b/Tests/DependencyInjection/SwarrotExtensionTest.php @@ -7,14 +7,6 @@ class SwarrotExtensionTest extends \PHPUnit_Framework_TestCase { - /** - * @expectedException \InvalidArgumentException - */ - public function test_it_rejects_invalid_providers() - { - $this->loadConfig($this->createContainer(), array('provider' => 'invalid')); - } - public function test_it_uses_the_default_connection_for_message_types() { $container = $this->createContainer();