Skip to content

Commit d8b9457

Browse files
authored
Merge pull request #649 from Eloar/master
producers and consumers autowiring arguments
2 parents 1b8288f + 9ff5eb1 commit d8b9457

File tree

3 files changed

+132
-10
lines changed

3 files changed

+132
-10
lines changed

DependencyInjection/OldSoundRabbitMqExtension.php

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22

33
namespace OldSound\RabbitMqBundle\DependencyInjection;
44

5+
use OldSound\RabbitMqBundle\RabbitMq\ConsumerInterface;
6+
use OldSound\RabbitMqBundle\RabbitMq\ProducerInterface;
57
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
6-
use Symfony\Component\DependencyInjection\ContainerInterface;
7-
use Symfony\Component\DependencyInjection\Extension\Extension;
8+
use Symfony\Component\Config\FileLocator;
89
use Symfony\Component\DependencyInjection\ContainerBuilder;
10+
use Symfony\Component\DependencyInjection\ContainerInterface;
911
use Symfony\Component\DependencyInjection\Definition;
10-
use Symfony\Component\DependencyInjection\Reference;
12+
use Symfony\Component\DependencyInjection\Extension\Extension;
1113
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
12-
use Symfony\Component\Config\FileLocator;
14+
use Symfony\Component\DependencyInjection\Reference;
1315

1416
/**
1517
* OldSoundRabbitMqExtension.
@@ -171,11 +173,32 @@ protected function loadProducers()
171173
if (null !== $producer['service_alias']) {
172174
$this->container->setAlias($producer['service_alias'], $producerServiceName);
173175
}
176+
177+
// register alias for argument auto wiring
178+
if (method_exists($this->container, 'registerAliasForArgument')) {
179+
$argName = !str_ends_with(strtolower($key), 'producer') ? sprintf('%sProducer', $key) : $key;
180+
$this->container
181+
->registerAliasForArgument($producerServiceName, ProducerInterface::class, $argName)
182+
->setPublic(false);
183+
184+
$this->container
185+
->registerAliasForArgument($producerServiceName, $producer['class'], $argName)
186+
->setPublic(false);
187+
}
174188
}
175189
} else {
176190
foreach ($this->config['producers'] as $key => $producer) {
177191
$definition = new Definition('%old_sound_rabbit_mq.fallback.class%');
178-
$this->container->setDefinition(sprintf('old_sound_rabbit_mq.%s_producer', $key), $definition);
192+
$producerServiceName = sprintf('old_sound_rabbit_mq.%s_producer', $key);
193+
$this->container->setDefinition($producerServiceName, $definition);
194+
195+
// register alias for argumen auto wiring
196+
if (method_exists($this->container, 'registerAliasForArgument')) {
197+
$argName = !str_ends_with(strtolower($key), 'producer') ? sprintf('%sProducer', $key) : $key;
198+
$this->container
199+
->registerAliasForArgument($producerServiceName, ProducerInterface::class, $argName)
200+
->setPublic(false);
201+
}
179202
}
180203
}
181204
}
@@ -242,6 +265,18 @@ protected function loadConsumers()
242265
$name = sprintf('old_sound_rabbit_mq.%s_consumer', $key);
243266
$this->container->setDefinition($name, $definition);
244267
$this->addDequeuerAwareCall($consumer['callback'], $name);
268+
269+
// register alias for argument auto wiring
270+
if (method_exists($this->container, 'registerAliasForArgument')) {
271+
$argName = !str_ends_with(strtolower($key), 'consumer') ? sprintf('%sConsumer', $key) : $key;
272+
$this->container
273+
->registerAliasForArgument($name, ConsumerInterface::class, $argName)
274+
->setPublic(false);
275+
276+
$this->container
277+
->registerAliasForArgument($name, '%old_sound_rabbit_mq.consumer.class%', $argName)
278+
->setPublic(false);
279+
}
245280
}
246281
}
247282

README.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,35 @@ consumers:
534534
qos_options: {prefetch_size: 0, prefetch_count: 1, global: false}
535535
```
536536

537+
### Autowiring producers and consumers ###
538+
539+
If used with **Symfony 4.2+** bundle declares in container set of aliases for producers and regular consumers. Those are
540+
used for arguments autowiring based on declared type and argument name. This allows you to change previous producer
541+
example to:
542+
543+
```php
544+
public function indexAction($name, ProducerInteface $uploadPictureProducer)
545+
{
546+
$msg = array('user_id' => 1235, 'image_path' => '/path/to/new/pic.png');
547+
$uploadPictureProducer->publish(serialize($msg));
548+
}
549+
```
550+
551+
Name of argument is constructed from producer or consumer name from configuration and suffixed with producer or consumer
552+
word according to type. In contrast to container items naming convention word suffix (producer or consumer) will not be
553+
duplicated if name is already suffixed. `upload_picture` producer key will be changed to `$uploadPictureProducer`
554+
argument name. `upload_picture_producer` producer key would also be aliased to `$uploadPictureProducer` argument name.
555+
It is best to avoid names similar in such manner.
556+
557+
All producers are aliased to `OldSound\RabbitMqBundle\RabbitMq\ProducerInterface` and producer class option from
558+
configuration. In sandbox mode only ProducerInterface aliases are made. It is highly recommended to use ProducerInterface
559+
class when type hinting arguments for producer injection.
560+
561+
All consumers are aliased to 'OldSound\RabbitMqBundle\RabbitMq\ConsumerInterface' and '%old_sound_rabbit_mq.consumer.class%'
562+
configuration option value. There is no difference between regular and sandbox mode. It is highly recommended to use
563+
ConsumerInterface when type hinting arguments for client injection.
564+
565+
537566
### Callbacks ###
538567

539568
Here's an example callback:
@@ -807,7 +836,7 @@ binding scenarios might include exchange to exchange bindings via `destination_i
807836
```yaml
808837
bindings:
809838
- {exchange: foo, destination: bar, routing_key: 'baz.*' }
810-
- {exchange: foo1, destination: foo, routing_key: 'baz.*' destination_is_exchange: true}
839+
- {exchange: foo1, destination: foo, routing_key: 'baz.*', destination_is_exchange: true}
811840
```
812841

813842
The rabbitmq:setup-fabric command will declare exchanges and queues as defined in your producer, consumer

Tests/DependencyInjection/OldSoundRabbitMqExtensionTest.php

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22

33
namespace OldSound\RabbitMqBundle\Tests\DependencyInjection;
44

5+
use OldSound\RabbitMqBundle\DependencyInjection\OldSoundRabbitMqExtension;
6+
use OldSound\RabbitMqBundle\RabbitMq\ConsumerInterface;
7+
use OldSound\RabbitMqBundle\RabbitMq\ProducerInterface;
8+
use PHPUnit\Framework\TestCase;
9+
use Symfony\Component\Config\FileLocator;
510
use Symfony\Component\DependencyInjection\ContainerBuilder;
611
use Symfony\Component\DependencyInjection\Definition;
7-
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
8-
use Symfony\Component\Config\FileLocator;
912
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
10-
use OldSound\RabbitMqBundle\DependencyInjection\OldSoundRabbitMqExtension;
13+
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
1114
use Symfony\Component\DependencyInjection\Reference;
12-
use PHPUnit\Framework\TestCase;
1315

1416
class OldSoundRabbitMqExtensionTest extends TestCase
1517
{
@@ -318,6 +320,35 @@ public function testFooProducerDefinition()
318320
$this->assertEquals('My\Foo\Producer', $definition->getClass());
319321
}
320322

323+
public function testProducerArgumentAliases()
324+
{
325+
/** @var ContainerBuilder $container */
326+
$container = $this->getContainer('test.yml');
327+
328+
if (!method_exists($container, 'registerAliasForArgument')) {
329+
// don't test if autowiring arguments functionality is not available
330+
return;
331+
}
332+
333+
// test expected aliases
334+
$expectedAliases = array(
335+
ProducerInterface::class . ' $fooProducer' => 'old_sound_rabbit_mq.foo_producer_producer',
336+
'My\Foo\Producer $fooProducer' => 'old_sound_rabbit_mq.foo_producer_producer',
337+
ProducerInterface::class . ' $fooProducerAliasedProducer' => 'old_sound_rabbit_mq.foo_producer_aliased_producer',
338+
'My\Foo\Producer $fooProducerAliasedProducer' => 'old_sound_rabbit_mq.foo_producer_aliased_producer',
339+
ProducerInterface::class . ' $defaultProducer' => 'old_sound_rabbit_mq.default_producer_producer',
340+
'%old_sound_rabbit_mq.producer.class% $defaultProducer' => 'old_sound_rabbit_mq.default_producer_producer',
341+
);
342+
343+
foreach($expectedAliases as $id => $target) {
344+
$this->assertTrue($container->hasAlias($id), sprintf('Container should have %s alias for autowiring support.', $id));
345+
346+
$alias = $container->getAlias($id);
347+
$this->assertEquals($target, (string)$alias, sprintf('Autowiring for %s should use %s.', $id, $target));
348+
$this->assertFalse($alias->isPublic(), sprintf('Autowiring alias for %s should be private', $id));
349+
}
350+
}
351+
321352
/**
322353
* @group alias
323354
*/
@@ -427,6 +458,33 @@ public function testFooConsumerDefinition()
427458
$this->assertEquals('%old_sound_rabbit_mq.consumer.class%', $definition->getClass());
428459
}
429460

461+
public function testConsumerArgumentAliases()
462+
{
463+
/** @var ContainerBuilder $container */
464+
$container = $this->getContainer('test.yml');
465+
466+
if (!method_exists($container, 'registerAliasForArgument')) {
467+
// don't test if autowiring arguments functionality is not available
468+
return;
469+
}
470+
471+
$expectedAliases = array(
472+
ConsumerInterface::class . ' $fooConsumer' => 'old_sound_rabbit_mq.foo_consumer_consumer',
473+
'%old_sound_rabbit_mq.consumer.class% $fooConsumer' => 'old_sound_rabbit_mq.foo_consumer_consumer',
474+
ConsumerInterface::class . ' $defaultConsumer' => 'old_sound_rabbit_mq.default_consumer_consumer',
475+
'%old_sound_rabbit_mq.consumer.class% $defaultConsumer' => 'old_sound_rabbit_mq.default_consumer_consumer',
476+
ConsumerInterface::class . ' $qosTestConsumer' => 'old_sound_rabbit_mq.qos_test_consumer_consumer',
477+
'%old_sound_rabbit_mq.consumer.class% $qosTestConsumer' => 'old_sound_rabbit_mq.qos_test_consumer_consumer'
478+
);
479+
foreach($expectedAliases as $id => $target) {
480+
$this->assertTrue($container->hasAlias($id), sprintf('Container should have %s alias for autowiring support.', $id));
481+
482+
$alias = $container->getAlias($id);
483+
$this->assertEquals($target, (string)$alias, sprintf('Autowiring for %s should use %s.', $id, $target));
484+
$this->assertFalse($alias->isPublic(), sprintf('Autowiring alias for %s should be private', $id));
485+
}
486+
}
487+
430488
public function testDefaultConsumerDefinition()
431489
{
432490
$container = $this->getContainer('test.yml');

0 commit comments

Comments
 (0)