diff --git a/src/Symfony/Component/Messenger/Attribute/Transport.php b/src/Symfony/Component/Messenger/Attribute/Transport.php new file mode 100644 index 0000000000000..a5da179ec44e3 --- /dev/null +++ b/src/Symfony/Component/Messenger/Attribute/Transport.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Attribute; + +/** + * @author Maxim Dovydenok + */ +#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)] +class Transport +{ + public function __construct(public readonly string $name) + { + } +} diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 98193ec5c02c4..3409acc041e13 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * Add `SerializedMessageStamp` to avoid serializing a message when a retry occurs. * Automatically resolve handled message type when method different from `__invoke` is used as handler. + * Add `Transport` attribute to configure message to sender mapping 6.0 --- diff --git a/src/Symfony/Component/Messenger/Tests/Fixtures/DummyMessageInterfaceWithAttribute.php b/src/Symfony/Component/Messenger/Tests/Fixtures/DummyMessageInterfaceWithAttribute.php new file mode 100644 index 0000000000000..0f9a78b34072a --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Fixtures/DummyMessageInterfaceWithAttribute.php @@ -0,0 +1,10 @@ +message = $message; + } + + public function getMessage(): string + { + return $this->message; + } +} + +#[\Attribute(\Attribute::TARGET_CLASS)] +class CustomTransport extends Transport +{ + public function __construct() + { + parent::__construct('message_attribute_sender_2'); + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Fixtures/DummyMessageWithAttributeAndInterface.php b/src/Symfony/Component/Messenger/Tests/Fixtures/DummyMessageWithAttributeAndInterface.php new file mode 100644 index 0000000000000..cb447a6a9b4a4 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Fixtures/DummyMessageWithAttributeAndInterface.php @@ -0,0 +1,21 @@ +message = $message; + } + + public function getMessage(): string + { + return $this->message; + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Sender/SendersLocatorTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Sender/SendersLocatorTest.php index db4cb0efa0782..f3ee2ab3a71ed 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Sender/SendersLocatorTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Sender/SendersLocatorTest.php @@ -15,12 +15,72 @@ use Psr\Container\ContainerInterface; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; +use Symfony\Component\Messenger\Tests\Fixtures\DummyMessageInterfaceWithAttribute; +use Symfony\Component\Messenger\Tests\Fixtures\DummyMessageWithAttribute; +use Symfony\Component\Messenger\Tests\Fixtures\DummyMessageWithAttributeAndInterface; use Symfony\Component\Messenger\Tests\Fixtures\SecondMessage; use Symfony\Component\Messenger\Transport\Sender\SenderInterface; use Symfony\Component\Messenger\Transport\Sender\SendersLocator; class SendersLocatorTest extends TestCase { + public function testAttributeMapping() + { + $sender = $this->createMock(SenderInterface::class); + $sendersLocator = $this->createContainer([ + 'message_attribute_sender' => $sender, + 'message_attribute_sender_2' => $sender, + 'interface_attribute_sender' => $sender, + 'message_config_sender' => $sender, + 'interface_config_sender' => $sender, + 'all_config_sender' => $sender, + ]); + + $locator = new SendersLocator([], $sendersLocator); + $this->assertSame([], iterator_to_array($locator->getSenders(new Envelope(new DummyMessage('a'))))); + $this->assertSame( + ['message_attribute_sender' => $sender, 'message_attribute_sender_2' => $sender], + iterator_to_array($locator->getSenders(new Envelope(new DummyMessageWithAttribute('a')))) + ); + $this->assertSame( + ['message_attribute_sender' => $sender, 'interface_attribute_sender' => $sender], + iterator_to_array($locator->getSenders(new Envelope(new DummyMessageWithAttributeAndInterface('a')))) + ); + + $locatorWithFullRouting = new SendersLocator([ + DummyMessageWithAttribute::class => ['message_config_sender'], + DummyMessageWithAttributeAndInterface::class => ['message_config_sender'], + DummyMessageInterfaceWithAttribute::class => ['interface_config_sender'], + '*' => ['all_config_sender'], + ], $sendersLocator); + $this->assertSame( + ['message_config_sender' => $sender, 'all_config_sender' => $sender], + iterator_to_array($locatorWithFullRouting->getSenders(new Envelope(new DummyMessageWithAttribute('a')))) + ); + $this->assertSame( + ['message_config_sender' => $sender, 'interface_config_sender' => $sender, 'all_config_sender' => $sender], + iterator_to_array($locatorWithFullRouting->getSenders(new Envelope(new DummyMessageWithAttributeAndInterface('a')))) + ); + + $locatorWithClassRouting = new SendersLocator([ + DummyMessageWithAttributeAndInterface::class => ['message_config_sender'], + '*' => ['all_config_sender'], + ], $sendersLocator); + $this->assertSame( + ['message_config_sender' => $sender, 'interface_attribute_sender' => $sender, 'all_config_sender' => $sender], + iterator_to_array($locatorWithClassRouting->getSenders(new Envelope(new DummyMessageWithAttributeAndInterface('a')))) + ); + + $locatorWithInterfaceRouting = new SendersLocator([ + DummyMessageInterfaceWithAttribute::class => ['interface_config_sender'], + '*' => ['all_config_sender'], + ], $sendersLocator); + $this->assertSame( + ['message_attribute_sender' => $sender, 'interface_config_sender' => $sender, 'all_config_sender' => $sender], + iterator_to_array($locatorWithInterfaceRouting->getSenders(new Envelope(new DummyMessageWithAttributeAndInterface('a')))) + ); + } + public function testItReturnsTheSenderBasedOnTheMessageClass() { $sender = $this->createMock(SenderInterface::class); diff --git a/src/Symfony/Component/Messenger/Transport/Sender/SendersLocator.php b/src/Symfony/Component/Messenger/Transport/Sender/SendersLocator.php index cda20008c8768..58b9be48a03c0 100644 --- a/src/Symfony/Component/Messenger/Transport/Sender/SendersLocator.php +++ b/src/Symfony/Component/Messenger/Transport/Sender/SendersLocator.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Messenger\Transport\Sender; use Psr\Container\ContainerInterface; +use Symfony\Component\Messenger\Attribute\Transport; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Exception\RuntimeException; use Symfony\Component\Messenger\Handler\HandlersLocator; @@ -41,20 +42,56 @@ public function __construct(array $sendersMap, ContainerInterface $sendersLocato */ public function getSenders(Envelope $envelope): iterable { - $seen = []; + $senderAliases = []; foreach (HandlersLocator::listTypes($envelope) as $type) { + $typeSenderAliases = []; + foreach ($this->sendersMap[$type] ?? [] as $senderAlias) { - if (!\in_array($senderAlias, $seen, true)) { - if (!$this->sendersLocator->has($senderAlias)) { - throw new RuntimeException(sprintf('Invalid senders configuration: sender "%s" is not in the senders locator.', $senderAlias)); - } - - $seen[] = $senderAlias; - $sender = $this->sendersLocator->get($senderAlias); - yield $senderAlias => $sender; - } + $typeSenderAliases[] = $senderAlias; + } + + if (!$typeSenderAliases) { + $typeSenderAliases = $this->getSendersFromAttributes($type); + } + + $senderAliases = array_merge($senderAliases, $typeSenderAliases); + } + + $senderAliases = array_unique($senderAliases); + + foreach ($senderAliases as $senderAlias) { + if (!$this->sendersLocator->has($senderAlias)) { + throw new RuntimeException(sprintf('Invalid senders configuration: sender "%s" is not in the senders locator.', $senderAlias)); } + + $sender = $this->sendersLocator->get($senderAlias); + yield $senderAlias => $sender; + } + } + + /** + * @return string[] + */ + private function getSendersFromAttributes(string $type): array + { + if (!class_exists($type) && !interface_exists($type)) { + return []; } + + try { + $reflectionClass = new \ReflectionClass($type); + } catch (\ReflectionException $e) { + return []; + } + + $attributes = $reflectionClass->getAttributes(Transport::class, \ReflectionAttribute::IS_INSTANCEOF); + + return array_map(function (\ReflectionAttribute $attribute): string { + /** @var Transport $attributeInstance */ + $attributeInstance = $attribute->newInstance(); + + return $attributeInstance->name; + }, $attributes); } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy