Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
feature #28275 [Messenger] Only subscribe to a given bus from the Mes…
…sageSubscriber (sroze)

This PR was merged into the 4.2-dev branch.

Discussion
----------

[Messenger] Only subscribe to a given bus from the MessageSubscriber

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #...   <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | ø

#27275 introduced the ability to listen to only a few buses from the handler tag. This adds that ability directly from the message subscriber.

It has also highlighted to me that most of the configuration can be done using `yield` (like the example I've added in this PR's tests) and that we could remove the support for other ways (especially the obscure `return [['method', -10]]` syntax) but I believe this should be done **in another pull-request** (that I'm happy to do after this one).

Commits
-------

f60e409 Only subscribe to a given bus from the MessageSubscriber
  • Loading branch information
sroze committed Aug 28, 2018
2 parents 4edbd60 + f60e409 commit bedd7aa
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 3 deletions.
Expand Up @@ -97,6 +97,7 @@ private function registerHandlers(ContainerBuilder $container, array $busIds)
$handlerBuses = (array) ($tag['bus'] ?? $busIds);

foreach ($handles as $messageClass => $method) {
$buses = $handlerBuses;
if (\is_int($messageClass)) {
$messageClass = $method;
$method = '__invoke';
Expand All @@ -110,8 +111,30 @@ private function registerHandlers(ContainerBuilder $container, array $busIds)
}

if (\is_array($method)) {
$messagePriority = $method[1];
$method = $method[0];
if (isset($method[0]) && isset($method[1])) {
$messagePriority = $method[1];
$method = $method[0];
} elseif (isset($method['method']) || isset($method['bus'])) {
if (isset($method['bus'])) {
if (!\in_array($method['bus'], $busIds)) {
$messageClassLocation = isset($tag['handles']) ? 'declared in your tag attribute "handles"' : $r->implementsInterface(MessageSubscriberInterface::class) ? sprintf('returned by method "%s::getHandledMessages()"', $r->getName()) : sprintf('used as argument type in method "%s::%s()"', $r->getName(), $method);

throw new RuntimeException(sprintf('Invalid configuration %s for message "%s": bus "%s" does not exist.', $messageClassLocation, $messageClass, $method['bus']));
}

$buses = array($method['bus']);
}

if (isset($method['priority'])) {
$messagePriority = $method['priority'];
}

$method = $method['method'] ?? '__invoke';
} else {
$messageClassLocation = isset($tag['handles']) ? 'declared in your tag attribute "handles"' : $r->implementsInterface(MessageSubscriberInterface::class) ? sprintf('returned by method "%s::getHandledMessages()"', $r->getName()) : sprintf('used as argument type in method "%s::%s()"', $r->getName(), $method);

throw new RuntimeException(sprintf('Invalid configuration %s for message "%s".', $messageClassLocation, $messageClass));
}
}

if (!\class_exists($messageClass)) {
Expand All @@ -132,7 +155,7 @@ private function registerHandlers(ContainerBuilder $container, array $busIds)
$definitionId = $serviceId;
}

foreach ($handlerBuses as $handlerBus) {
foreach ($buses as $handlerBus) {
$handlersByBusAndMessage[$handlerBus][$messageClass][$messagePriority][] = $definitionId;
}
}
Expand Down
Expand Up @@ -297,6 +297,48 @@ public function testItShouldNotThrowIfGeneratorIsReturnedInsteadOfArray()
$this->assertEquals(array(new Reference(HandlerWithGenerators::class), 'secondMessage'), $container->getDefinition($secondReference)->getArgument(0));
}

public function testItRegistersHandlersOnDifferentBuses()
{
$container = $this->getContainerBuilder($eventsBusId = 'event_bus');
$container->register($commandsBusId = 'command_bus', MessageBusInterface::class)->addTag('messenger.bus')->setArgument(0, array());

$container
->register(HandlerOnSpecificBuses::class, HandlerOnSpecificBuses::class)
->addTag('messenger.message_handler')
;

(new MessengerPass())->process($container);

$eventsHandlerLocatorDefinition = $container->getDefinition($container->getDefinition($eventsBusId.'.messenger.handler_resolver')->getArgument(0));
$eventsHandlerMapping = $eventsHandlerLocatorDefinition->getArgument(0);

$this->assertEquals(array('handler.'.DummyMessage::class), array_keys($eventsHandlerMapping));
$firstReference = $eventsHandlerMapping['handler.'.DummyMessage::class]->getValues()[0];
$this->assertEquals(array(new Reference(HandlerOnSpecificBuses::class), 'dummyMethodForEvents'), $container->getDefinition($firstReference)->getArgument(0));

$commandsHandlerLocatorDefinition = $container->getDefinition($container->getDefinition($commandsBusId.'.messenger.handler_resolver')->getArgument(0));
$commandsHandlerMapping = $commandsHandlerLocatorDefinition->getArgument(0);

$this->assertEquals(array('handler.'.DummyMessage::class), array_keys($commandsHandlerMapping));
$firstReference = $commandsHandlerMapping['handler.'.DummyMessage::class]->getValues()[0];
$this->assertEquals(array(new Reference(HandlerOnSpecificBuses::class), 'dummyMethodForCommands'), $container->getDefinition($firstReference)->getArgument(0));
}

/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Invalid configuration returned by method "Symfony\Component\Messenger\Tests\DependencyInjection\HandlerOnUndefinedBus::getHandledMessages()" for message "Symfony\Component\Messenger\Tests\Fixtures\DummyMessage": bus "some_undefined_bus" does not exist.
*/
public function testItThrowsAnExceptionOnUnknownBus()
{
$container = $this->getContainerBuilder();
$container
->register(HandlerOnUndefinedBus::class, HandlerOnUndefinedBus::class)
->addTag('messenger.message_handler')
;

(new MessengerPass())->process($container);
}

/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Invalid sender "app.messenger.sender": class "Symfony\Component\Messenger\Tests\DependencyInjection\InvalidSender" must implement interface "Symfony\Component\Messenger\Transport\SenderInterface".
Expand Down Expand Up @@ -747,6 +789,35 @@ public function secondMessage()
}
}

class HandlerOnSpecificBuses implements MessageSubscriberInterface
{
public static function getHandledMessages(): iterable
{
yield DummyMessage::class => array('method' => 'dummyMethodForEvents', 'bus' => 'event_bus');
yield DummyMessage::class => array('method' => 'dummyMethodForCommands', 'bus' => 'command_bus');
}

public function dummyMethodForEvents()
{
}

public function dummyMethodForCommands()
{
}
}

class HandlerOnUndefinedBus implements MessageSubscriberInterface
{
public static function getHandledMessages(): iterable
{
yield DummyMessage::class => array('method' => 'dummyMethodForSomeBus', 'bus' => 'some_undefined_bus');
}

public function dummyMethodForSomeBus()
{
}
}

class UselessMiddleware implements MiddlewareInterface
{
public function handle($message, callable $next)
Expand Down

0 comments on commit bedd7aa

Please sign in to comment.