[Messenger] added a SenderLocator decoupled from ContainerInterface
This commit is contained in:
parent
f2f4cd82c3
commit
e658e155aa
@ -8,7 +8,7 @@
|
||||
<defaults public="false" />
|
||||
|
||||
<!-- Asynchronous -->
|
||||
<service id="messenger.asynchronous.routing.sender_locator" class="Symfony\Component\Messenger\Asynchronous\Routing\SenderLocator">
|
||||
<service id="messenger.asynchronous.routing.sender_locator" class="Symfony\Component\Messenger\Asynchronous\Routing\ContainerSenderLocator">
|
||||
<argument type="service" id="messenger.sender_locator" />
|
||||
<argument type="collection" /> <!-- Message to sender ID mapping -->
|
||||
</service>
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
namespace Symfony\Component\Messenger\Asynchronous\Middleware;
|
||||
|
||||
use Symfony\Component\Messenger\Asynchronous\Routing\SenderLocator;
|
||||
use Symfony\Component\Messenger\Asynchronous\Routing\AbstractSenderLocator;
|
||||
use Symfony\Component\Messenger\Asynchronous\Routing\SenderLocatorInterface;
|
||||
use Symfony\Component\Messenger\Asynchronous\Transport\ReceivedMessage;
|
||||
use Symfony\Component\Messenger\Envelope;
|
||||
@ -60,6 +60,6 @@ class SendMessageMiddleware implements MiddlewareInterface, EnvelopeAwareInterfa
|
||||
|
||||
private function mustSendAndHandle($message): bool
|
||||
{
|
||||
return (bool) SenderLocator::getValueFromMessageRouting($this->messagesToSendAndHandleMapping, $message);
|
||||
return (bool) AbstractSenderLocator::getValueFromMessageRouting($this->messagesToSendAndHandleMapping, $message);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Messenger\Asynchronous\Routing;
|
||||
|
||||
/**
|
||||
* @author Samuel Roze <samuel.roze@gmail.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
abstract class AbstractSenderLocator implements SenderLocatorInterface
|
||||
{
|
||||
public static function getValueFromMessageRouting(array $mapping, $message)
|
||||
{
|
||||
if (isset($mapping[\get_class($message)])) {
|
||||
return $mapping[\get_class($message)];
|
||||
}
|
||||
if ($parentsMapping = array_intersect_key($mapping, class_parents($message))) {
|
||||
return current($parentsMapping);
|
||||
}
|
||||
if ($interfaceMapping = array_intersect_key($mapping, class_implements($message))) {
|
||||
return current($interfaceMapping);
|
||||
}
|
||||
if (isset($mapping['*'])) {
|
||||
return $mapping['*'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Messenger\Asynchronous\Routing;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\Messenger\Transport\SenderInterface;
|
||||
|
||||
/**
|
||||
* @author Samuel Roze <samuel.roze@gmail.com>
|
||||
*/
|
||||
class ContainerSenderLocator extends AbstractSenderLocator
|
||||
{
|
||||
private $senderServiceLocator;
|
||||
private $messageToSenderIdMapping;
|
||||
|
||||
public function __construct(ContainerInterface $senderServiceLocator, array $messageToSenderIdMapping)
|
||||
{
|
||||
$this->senderServiceLocator = $senderServiceLocator;
|
||||
$this->messageToSenderIdMapping = $messageToSenderIdMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSenderForMessage($message): ?SenderInterface
|
||||
{
|
||||
$senderId = self::getValueFromMessageRouting($this->messageToSenderIdMapping, $message);
|
||||
|
||||
return $senderId ? $this->senderServiceLocator->get($senderId) : null;
|
||||
}
|
||||
}
|
@ -11,21 +11,19 @@
|
||||
|
||||
namespace Symfony\Component\Messenger\Asynchronous\Routing;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\Messenger\Exception\RuntimeException;
|
||||
use Symfony\Component\Messenger\Transport\SenderInterface;
|
||||
|
||||
/**
|
||||
* @author Samuel Roze <samuel.roze@gmail.com>
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class SenderLocator implements SenderLocatorInterface
|
||||
class SenderLocator extends AbstractSenderLocator
|
||||
{
|
||||
private $senderServiceLocator;
|
||||
private $messageToSenderIdMapping;
|
||||
private $messageToSenderMapping;
|
||||
|
||||
public function __construct(ContainerInterface $senderServiceLocator, array $messageToSenderIdMapping)
|
||||
public function __construct(array $messageToSenderMapping)
|
||||
{
|
||||
$this->senderServiceLocator = $senderServiceLocator;
|
||||
$this->messageToSenderIdMapping = $messageToSenderIdMapping;
|
||||
$this->messageToSenderMapping = $messageToSenderMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33,34 +31,15 @@ class SenderLocator implements SenderLocatorInterface
|
||||
*/
|
||||
public function getSenderForMessage($message): ?SenderInterface
|
||||
{
|
||||
$senderId = $this->getSenderId($message);
|
||||
|
||||
return $senderId ? $this->senderServiceLocator->get($senderId) : null;
|
||||
}
|
||||
|
||||
private function getSenderId($message): ?string
|
||||
{
|
||||
return self::getValueFromMessageRouting($this->messageToSenderIdMapping, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function getValueFromMessageRouting(array $mapping, $message)
|
||||
{
|
||||
if (isset($mapping[\get_class($message)])) {
|
||||
return $mapping[\get_class($message)];
|
||||
}
|
||||
if ($parentsMapping = array_intersect_key($mapping, class_parents($message))) {
|
||||
return current($parentsMapping);
|
||||
}
|
||||
if ($interfaceMapping = array_intersect_key($mapping, class_implements($message))) {
|
||||
return current($interfaceMapping);
|
||||
}
|
||||
if (isset($mapping['*'])) {
|
||||
return $mapping['*'];
|
||||
$sender = self::getValueFromMessageRouting($this->messageToSenderMapping, $message);
|
||||
if (null === $sender) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
if (!$sender instanceof SenderInterface) {
|
||||
throw new RuntimeException(sprintf('The sender instance provided for message "%s" should be of type "%s" but got "%s".', \get_class($message), SenderInterface::class, \is_object($sender) ? \get_class($sender) : \gettype($sender)));
|
||||
}
|
||||
|
||||
return $sender;
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,9 @@ CHANGELOG
|
||||
4.2.0
|
||||
-----
|
||||
|
||||
* [BC BREAK] `SenderLocator` has been renamed to `ContainerSenderLocator`
|
||||
Be careful as there is still a `SenderLocator` class, but it does not rely on a `ContainerInterface` to find senders.
|
||||
Instead, it accepts the sender instance itself instead of its identifier in the container.
|
||||
* [BC BREAK] `MessageSubscriberInterface::getHandledMessages()` return value has changed. The value of an array item
|
||||
needs to be an associative array or the method name.
|
||||
* `ValidationMiddleware::handle()` and `SendMessageMiddleware::handle()` now require an `Envelope` object
|
||||
|
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Messenger\Exception;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class RuntimeException extends \RuntimeException implements ExceptionInterface
|
||||
{
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Messenger\Tests\Asynchronous\Routing;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\Messenger\Asynchronous\Routing\ContainerSenderLocator;
|
||||
use Symfony\Component\Messenger\Tests\Fixtures\ChildDummyMessage;
|
||||
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
|
||||
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessageInterface;
|
||||
use Symfony\Component\Messenger\Tests\Fixtures\SecondMessage;
|
||||
use Symfony\Component\Messenger\Transport\SenderInterface;
|
||||
|
||||
class ContainerSenderLocatorTest extends TestCase
|
||||
{
|
||||
public function testItReturnsTheSenderBasedOnTheMessageClass()
|
||||
{
|
||||
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
|
||||
$container = new Container();
|
||||
$container->set('my_amqp_sender', $sender);
|
||||
|
||||
$locator = new ContainerSenderLocator($container, array(
|
||||
DummyMessage::class => 'my_amqp_sender',
|
||||
));
|
||||
|
||||
$this->assertSame($sender, $locator->getSenderForMessage(new DummyMessage('Hello')));
|
||||
$this->assertNull($locator->getSenderForMessage(new SecondMessage()));
|
||||
}
|
||||
|
||||
public function testItReturnsTheSenderBasedOnTheMessageParentClass()
|
||||
{
|
||||
$container = new Container();
|
||||
|
||||
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
|
||||
$container->set('my_amqp_sender', $sender);
|
||||
|
||||
$apiSender = $this->getMockBuilder(SenderInterface::class)->getMock();
|
||||
$container->set('my_api_sender', $apiSender);
|
||||
|
||||
$locator = new ContainerSenderLocator($container, array(
|
||||
DummyMessageInterface::class => 'my_api_sender',
|
||||
DummyMessage::class => 'my_amqp_sender',
|
||||
));
|
||||
|
||||
$this->assertSame($sender, $locator->getSenderForMessage(new ChildDummyMessage('Hello')));
|
||||
$this->assertNull($locator->getSenderForMessage(new SecondMessage()));
|
||||
}
|
||||
|
||||
public function testItReturnsTheSenderBasedOnTheMessageInterface()
|
||||
{
|
||||
$container = new Container();
|
||||
|
||||
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
|
||||
$container->set('my_amqp_sender', $sender);
|
||||
|
||||
$locator = new ContainerSenderLocator($container, array(
|
||||
DummyMessageInterface::class => 'my_amqp_sender',
|
||||
));
|
||||
|
||||
$this->assertSame($sender, $locator->getSenderForMessage(new DummyMessage('Hello')));
|
||||
$this->assertNull($locator->getSenderForMessage(new SecondMessage()));
|
||||
}
|
||||
|
||||
public function testItSupportsAWildcardInsteadOfTheMessageClass()
|
||||
{
|
||||
$container = new Container();
|
||||
|
||||
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
|
||||
$container->set('my_amqp_sender', $sender);
|
||||
|
||||
$apiSender = $this->getMockBuilder(SenderInterface::class)->getMock();
|
||||
$container->set('my_api_sender', $apiSender);
|
||||
|
||||
$locator = new ContainerSenderLocator($container, array(
|
||||
DummyMessage::class => 'my_amqp_sender',
|
||||
'*' => 'my_api_sender',
|
||||
));
|
||||
|
||||
$this->assertSame($sender, $locator->getSenderForMessage(new DummyMessage('Hello')));
|
||||
$this->assertSame($apiSender, $locator->getSenderForMessage(new SecondMessage()));
|
||||
}
|
||||
}
|
@ -12,11 +12,9 @@
|
||||
namespace Symfony\Component\Messenger\Tests\Asynchronous\Routing;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\Messenger\Asynchronous\Routing\SenderLocator;
|
||||
use Symfony\Component\Messenger\Tests\Fixtures\ChildDummyMessage;
|
||||
use Symfony\Component\Messenger\Exception\RuntimeException;
|
||||
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
|
||||
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessageInterface;
|
||||
use Symfony\Component\Messenger\Tests\Fixtures\SecondMessage;
|
||||
use Symfony\Component\Messenger\Transport\SenderInterface;
|
||||
|
||||
@ -25,67 +23,21 @@ class SenderLocatorTest extends TestCase
|
||||
public function testItReturnsTheSenderBasedOnTheMessageClass()
|
||||
{
|
||||
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
|
||||
$container = new Container();
|
||||
$container->set('my_amqp_sender', $sender);
|
||||
|
||||
$locator = new SenderLocator($container, array(
|
||||
DummyMessage::class => 'my_amqp_sender',
|
||||
$locator = new SenderLocator(array(
|
||||
DummyMessage::class => $sender,
|
||||
));
|
||||
|
||||
$this->assertSame($sender, $locator->getSenderForMessage(new DummyMessage('Hello')));
|
||||
$this->assertNull($locator->getSenderForMessage(new SecondMessage()));
|
||||
}
|
||||
|
||||
public function testItReturnsTheSenderBasedOnTheMessageParentClass()
|
||||
public function testItThrowsExceptionIfConfigurationIsWrong()
|
||||
{
|
||||
$container = new Container();
|
||||
|
||||
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
|
||||
$container->set('my_amqp_sender', $sender);
|
||||
|
||||
$apiSender = $this->getMockBuilder(SenderInterface::class)->getMock();
|
||||
$container->set('my_api_sender', $apiSender);
|
||||
|
||||
$locator = new SenderLocator($container, array(
|
||||
DummyMessageInterface::class => 'my_api_sender',
|
||||
DummyMessage::class => 'my_amqp_sender',
|
||||
$locator = new SenderLocator(array(
|
||||
DummyMessage::class => 'amqp',
|
||||
));
|
||||
|
||||
$this->assertSame($sender, $locator->getSenderForMessage(new ChildDummyMessage('Hello')));
|
||||
$this->assertNull($locator->getSenderForMessage(new SecondMessage()));
|
||||
}
|
||||
|
||||
public function testItReturnsTheSenderBasedOnTheMessageInterface()
|
||||
{
|
||||
$container = new Container();
|
||||
|
||||
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
|
||||
$container->set('my_amqp_sender', $sender);
|
||||
|
||||
$locator = new SenderLocator($container, array(
|
||||
DummyMessageInterface::class => 'my_amqp_sender',
|
||||
));
|
||||
|
||||
$this->assertSame($sender, $locator->getSenderForMessage(new DummyMessage('Hello')));
|
||||
$this->assertNull($locator->getSenderForMessage(new SecondMessage()));
|
||||
}
|
||||
|
||||
public function testItSupportsAWildcardInsteadOfTheMessageClass()
|
||||
{
|
||||
$container = new Container();
|
||||
|
||||
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
|
||||
$container->set('my_amqp_sender', $sender);
|
||||
|
||||
$apiSender = $this->getMockBuilder(SenderInterface::class)->getMock();
|
||||
$container->set('my_api_sender', $apiSender);
|
||||
|
||||
$locator = new SenderLocator($container, array(
|
||||
DummyMessage::class => 'my_amqp_sender',
|
||||
'*' => 'my_api_sender',
|
||||
));
|
||||
|
||||
$this->assertSame($sender, $locator->getSenderForMessage(new DummyMessage('Hello')));
|
||||
$this->assertSame($apiSender, $locator->getSenderForMessage(new SecondMessage()));
|
||||
$this->expectException(RuntimeException::class);
|
||||
$locator->getSenderForMessage(new DummyMessage('Hello'));
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user