From ebbfac2d22898a324557c5692ce03242713438b7 Mon Sep 17 00:00:00 2001 From: Nicolas PHILIPPE Date: Sat, 8 Jan 2022 14:38:34 +0100 Subject: [PATCH] [Messenger] availability to add serializer config at transport level --- .../DependencyInjection/Configuration.php | 12 +++++++ .../FrameworkExtension.php | 21 ++++++++++-- .../messenger_transport_serializer_config.php | 22 +++++++++++++ ...er_transport_serializer_config_invalid.php | 14 ++++++++ .../messenger_transport_serializer_config.xml | 26 +++++++++++++++ ...er_transport_serializer_config_invalid.xml | 15 +++++++++ .../messenger_transport_serializer_config.yml | 15 +++++++++ ...er_transport_serializer_config_invalid.yml | 7 ++++ .../FrameworkExtensionTest.php | 33 +++++++++++++++++-- src/Symfony/Component/Messenger/CHANGELOG.md | 1 + ...rmatAndContextAwareSerializerInterface.php | 22 +++++++++++++ .../FormatAndContextAwareSerializerTrait.php | 31 +++++++++++++++++ .../Transport/Serialization/Serializer.php | 10 +++--- 13 files changed, 220 insertions(+), 9 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_config.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_config_invalid.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_config.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_config_invalid.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_config.yml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_config_invalid.yml create mode 100644 src/Symfony/Component/Messenger/Transport/Serialization/FormatAndContextAwareSerializerInterface.php create mode 100644 src/Symfony/Component/Messenger/Transport/Serialization/FormatAndContextAwareSerializerTrait.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 5f2eb5daa173e..9d712f3ab0b4f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -1386,6 +1386,18 @@ function ($a) { ->children() ->scalarNode('dsn')->end() ->scalarNode('serializer')->defaultNull()->info('Service id of a custom serializer to use.')->end() + ->arrayNode('symfony_serializer') + ->children() + ->scalarNode('format')->defaultNull()->info('Serialization format for the messenger.transport.symfony_serializer service (which is not the serializer used by default).')->end() + ->arrayNode('context') + ->normalizeKeys(false) + ->useAttributeAsKey('name') + ->defaultValue([]) + ->info('Context array for the messenger.transport.symfony_serializer service (which is not the serializer used by default).') + ->prototype('variable')->end() + ->end() + ->end() + ->end() ->arrayNode('options') ->normalizeKeys(false) ->defaultValue([]) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 02b4e24666449..0de2d4b014a2f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -107,6 +107,7 @@ use Symfony\Component\Messenger\MessageBus; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Messenger\Middleware\RouterContextMiddleware; +use Symfony\Component\Messenger\Transport\Serialization\FormatAndContextAwareSerializerInterface; use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; use Symfony\Component\Messenger\Transport\TransportFactoryInterface; use Symfony\Component\Messenger\Transport\TransportInterface; @@ -1947,8 +1948,8 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder $container->removeAlias(SerializerInterface::class); } else { $container->getDefinition('messenger.transport.symfony_serializer') - ->replaceArgument(1, $config['serializer']['symfony_serializer']['format']) - ->replaceArgument(2, $config['serializer']['symfony_serializer']['context']); + ->addMethodCall('setFormat', [$config['serializer']['symfony_serializer']['format']]) + ->addMethodCall('setContext', [$config['serializer']['symfony_serializer']['context']]); $container->setAlias('messenger.default_serializer', $config['serializer']['default_serializer']); } @@ -1976,6 +1977,22 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder $transportRetryReferences = []; foreach ($config['transports'] as $name => $transport) { $serializerId = $transport['serializer'] ?? 'messenger.default_serializer'; + + if (isset($transport['symfony_serializer'])) { + $serializerDefinition = $container->findDefinition($serializerId); + + if (!isset(class_implements($serializerDefinition->getClass())[FormatAndContextAwareSerializerInterface::class])) { + throw new InvalidArgumentException(sprintf('Serializer for transport "%s" should implement "%s" in order to have custom format or context.', $name, FormatAndContextAwareSerializerInterface::class)); + } + + $container->setDefinition($serializerWithCustomConfigurationId = "messenger.transport.{$name}.serializer", new ChildDefinition($serializerId)) + ->addMethodCall('setFormat', [$transport['symfony_serializer']['format'] ?? $config['serializer']['symfony_serializer']['format']]) + ->addMethodCall('setContext', [($transport['symfony_serializer']['context'] ?? []) + $config['serializer']['symfony_serializer']['context']]) + ; + + $serializerId = $serializerWithCustomConfigurationId; + } + $transportDefinition = (new Definition(TransportInterface::class)) ->setFactory([new Reference('messenger.transport_factory'), 'createTransport']) ->setArguments([$transport['dsn'], $transport['options'] + ['transport_name' => $name], new Reference($serializerId)]) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_config.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_config.php new file mode 100644 index 0000000000000..0212b2084cfe6 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_config.php @@ -0,0 +1,22 @@ +loadFromExtension('framework', [ + 'messenger' => [ + 'serializer' => [ + 'default_serializer' => 'messenger.transport.symfony_serializer', + 'symfony_serializer' => [ + 'format' => 'json', + 'context' => ['some_context' => true] + ] + ], + 'transports' => [ + 'foo' => [ + 'dsn' => 'null://', + 'symfony_serializer' => [ + 'format' => 'xml', + 'context' => ['some_other_context' => true] + ] + ], + ], + ], +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_config_invalid.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_config_invalid.php new file mode 100644 index 0000000000000..e9b877331adb1 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_config_invalid.php @@ -0,0 +1,14 @@ +loadFromExtension('framework', [ + 'messenger' => [ + 'transports' => [ + 'foo' => [ + 'dsn' => 'null://', + 'symfony_serializer' => [ + 'format' => 'xml', + ] + ], + ], + ], +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_config.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_config.xml new file mode 100644 index 0000000000000..0be337bf7b2ba --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_config.xml @@ -0,0 +1,26 @@ + + + + + + + + + true + + + + + + + true + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_config_invalid.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_config_invalid.xml new file mode 100644 index 0000000000000..f7a1184b6c492 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_config_invalid.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_config.yml new file mode 100644 index 0000000000000..297d6f17ec029 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_config.yml @@ -0,0 +1,15 @@ +framework: + messenger: + serializer: + default_serializer: messenger.transport.symfony_serializer + symfony_serializer: + format: 'json' + context: + some_context: true + transports: + foo: + dsn: 'null://' + symfony_serializer: + format: 'xml' + context: + some_other_context: true diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_config_invalid.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_config_invalid.yml new file mode 100644 index 0000000000000..667c1bd788a8d --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_config_invalid.yml @@ -0,0 +1,7 @@ +framework: + messenger: + transports: + foo: + dsn: 'null://' + symfony_serializer: + format: 'xml' diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index c054edd268ad1..21c462a8b107c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -37,6 +37,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Loader\ClosureLoader; use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag; @@ -901,8 +902,13 @@ public function testMessengerTransportConfiguration() $this->assertSame('messenger.transport.symfony_serializer', (string) $container->getAlias('messenger.default_serializer')); $serializerTransportDefinition = $container->getDefinition('messenger.transport.symfony_serializer'); - $this->assertSame('csv', $serializerTransportDefinition->getArgument(1)); - $this->assertSame(['enable_max_depth' => true], $serializerTransportDefinition->getArgument(2)); + self::assertSame( + [ + ['setFormat', ['csv']], + ['setContext', [['enable_max_depth' => true]]], + ], + $serializerTransportDefinition->getMethodCalls() + ); } public function testMessengerWithMultipleBuses() @@ -955,6 +961,29 @@ public function testMessengerInvalidTransportRouting() $this->createContainerFromFile('messenger_routing_invalid_transport'); } + public function testMessengerWithTransportSerializerConfig() + { + $container = $this->createContainerFromFile('messenger_transport_serializer_config'); + self::assertTrue($container->has('messenger.transport.foo.serializer')); + + $serializerDefinition = $container->findDefinition('messenger.transport.foo.serializer'); + self::assertSame( + [ + ['setFormat', ['xml']], + ['setContext', [['some_other_context' => true, 'some_context' => true]]], + ], + $serializerDefinition->getMethodCalls() + ); + } + + public function testMessengerWithTransportSerializerConfigThrowsIfWrongSerializerClass() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Serializer for transport "foo" should implement "Symfony\Component\Messenger\Transport\Serialization\FormatAndContextAwareSerializerInterface" in order to have custom format or context.'); + + $this->createContainerFromFile('messenger_transport_serializer_config_invalid'); + } + public function testTranslator() { $container = $this->createContainerFromFile('full'); diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 14b38194898ff..e1a2de21470ea 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Add `SerializedMessageStamp` to avoid serializing a message when a retry occurs. + * Add serializer configuration at transport level. 6.0 --- diff --git a/src/Symfony/Component/Messenger/Transport/Serialization/FormatAndContextAwareSerializerInterface.php b/src/Symfony/Component/Messenger/Transport/Serialization/FormatAndContextAwareSerializerInterface.php new file mode 100644 index 0000000000000..c200fbdc461ff --- /dev/null +++ b/src/Symfony/Component/Messenger/Transport/Serialization/FormatAndContextAwareSerializerInterface.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Serialization; + +/** + * @author Nicolas PHILIPPE + */ +interface FormatAndContextAwareSerializerInterface extends SerializerInterface +{ + public function setFormat(string $format): void; + + public function setContext(array $context): void; +} diff --git a/src/Symfony/Component/Messenger/Transport/Serialization/FormatAndContextAwareSerializerTrait.php b/src/Symfony/Component/Messenger/Transport/Serialization/FormatAndContextAwareSerializerTrait.php new file mode 100644 index 0000000000000..8f065a975ffe0 --- /dev/null +++ b/src/Symfony/Component/Messenger/Transport/Serialization/FormatAndContextAwareSerializerTrait.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Serialization; + +/** + * @author Nicolas PHILIPPE + */ +trait FormatAndContextAwareSerializerTrait +{ + private string $format; + private array $context; + + public function setFormat(string $format): void + { + $this->format = $format; + } + + public function setContext(array $context): void + { + $this->context = $context + [Serializer::MESSENGER_SERIALIZATION_CONTEXT => true]; + } +} diff --git a/src/Symfony/Component/Messenger/Transport/Serialization/Serializer.php b/src/Symfony/Component/Messenger/Transport/Serialization/Serializer.php index b3c8cb7c6ef3f..9c7ded82a5197 100644 --- a/src/Symfony/Component/Messenger/Transport/Serialization/Serializer.php +++ b/src/Symfony/Component/Messenger/Transport/Serialization/Serializer.php @@ -29,20 +29,20 @@ /** * @author Samuel Roze */ -class Serializer implements SerializerInterface +class Serializer implements FormatAndContextAwareSerializerInterface { + use FormatAndContextAwareSerializerTrait; + public const MESSENGER_SERIALIZATION_CONTEXT = 'messenger_serialization'; private const STAMP_HEADER_PREFIX = 'X-Message-Stamp-'; private SymfonySerializerInterface $serializer; - private string $format; - private array $context; public function __construct(SymfonySerializerInterface $serializer = null, string $format = 'json', array $context = []) { $this->serializer = $serializer ?? self::create()->serializer; - $this->format = $format; - $this->context = $context + [self::MESSENGER_SERIALIZATION_CONTEXT => true]; + $this->setFormat($format); + $this->setContext($context); } public static function create(): self