diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
index 772c8fe1ffeb7..aac1d4a9fd42a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
@@ -1466,9 +1466,75 @@ function ($a) {
})
->end()
->fixXmlConfig('option')
+ ->validate()
+ ->ifTrue(static fn (array $transportConf) => \count(array_intersect(['serializer', 'incoming_message_serializer', 'outgoing_message_serializer'], array_keys($transportConf))) > 1)
+ ->thenInvalid('Only one of "serializer", "incoming_message_serializer" and "outgoing_message_serializer" could be used.')
+ ->end()
->children()
->scalarNode('dsn')->end()
- ->scalarNode('serializer')->defaultNull()->info('Service id of a custom serializer to use.')->end()
+ ->arrayNode('serializer')
+ ->info('Transport serializer configuration for messages produced and handled by this application.')
+ ->beforeNormalization()
+ ->ifString()
+ ->then(static fn (string $serviceId) => ['service_id' => $serviceId])
+ ->end()
+ ->children()
+ ->scalarNode('service_id')->info('Service id of a custom transport serializer to use (incompatible with "format", "context" and "serializer" options).')->defaultNull()->end()
+ ->scalarNode('format')->info('Serialization format for this transport\'s serializer (will use Symfony serializer).')->end()
+ ->arrayNode('context')
+ ->normalizeKeys(false)
+ ->useAttributeAsKey('name')
+ ->defaultValue([])
+ ->info('Context serialization array for this transport\'s serializer (will use Symfony serializer).')
+ ->prototype('variable')->end()
+ ->end()
+ ->scalarNode('serializer')->info('Service id of a custom Symfony serializer to use.')->end()
+ ->end()
+ ->validate()
+ ->ifTrue(static fn (array $serializerConf) => !(isset($serializerConf['service_id']) xor (isset($serializerConf['format']) || [] !== $serializerConf['context'] || isset($serializerConf['serializer']))))
+ ->thenInvalid('Either "service_id" OR at least one of "format" or "context" or "serializer" should be provided.')
+ ->end()
+ ->end()
+ ->arrayNode('incoming_message_serializer')
+ ->info('Transport serializer configuration for messages coming from other applications (uses Symfony serializer).')
+ ->children()
+ ->scalarNode('messageClass')
+ ->info('The class in which the message should be deserialized (incompatible with "messageClassResolver" option).')
+ ->validate()
+ ->ifTrue(static fn ($class) => $class && !class_exists($class))
+ ->thenInvalid('The "messageClass" should be a valid class.')
+ ->end()
+ ->end()
+ ->scalarNode('messageClassResolver')->info('Service id of a message class resolver to use (incompatible with "messageClass" option).')->end()
+ ->scalarNode('format')->info('Serialization format for this transport\'s serializer.')->end()
+ ->arrayNode('context')
+ ->normalizeKeys(false)
+ ->useAttributeAsKey('name')
+ ->defaultValue([])
+ ->info('Context serialization array for this transport\'s serializer.')
+ ->prototype('variable')->end()
+ ->end()
+ ->scalarNode('serializer')->info('Service id of a custom Symfony serializer to use.')->end()
+ ->end()
+ ->validate()
+ ->ifTrue(static fn (array $incomingMessageConf) => !(isset($incomingMessageConf['messageClass']) xor isset($incomingMessageConf['messageClassResolver'])))
+ ->thenInvalid('A message class OR a message class resolver should be provided.')
+ ->end()
+ ->end()
+ ->arrayNode('outgoing_message_serializer')
+ ->info('Transport serializer configuration for sending messages to other applications (uses Symfony serializer).')
+ ->children()
+ ->scalarNode('format')->info('Serialization format for this transport\'s serializer.')->end()
+ ->arrayNode('context')
+ ->normalizeKeys(false)
+ ->useAttributeAsKey('name')
+ ->defaultValue([])
+ ->info('Context serialization array for this transport\'s serializer.')
+ ->prototype('variable')->end()
+ ->end()
+ ->scalarNode('serializer')->info('Service id of a custom Symfony serializer to use.')->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 358ec36f10bea..01a59bf609f88 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -120,6 +120,9 @@
use Symfony\Component\Messenger\MessageBus;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Messenger\Middleware\RouterContextMiddleware;
+use Symfony\Component\Messenger\Transport\Serialization\IncomingMessageSerializer;
+use Symfony\Component\Messenger\Transport\Serialization\OutgoingMessageSerializer;
+use Symfony\Component\Messenger\Transport\Serialization\Serializer;
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;
use Symfony\Component\Messenger\Transport\TransportFactoryInterface;
use Symfony\Component\Messenger\Transport\TransportInterface;
@@ -2086,7 +2089,47 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder
$transportRetryReferences = [];
$transportRateLimiterReferences = [];
foreach ($config['transports'] as $name => $transport) {
- $serializerId = $transport['serializer'] ?? 'messenger.default_serializer';
+ if (isset($transport['serializer'])) {
+ $basicSerializerConf = $transport['serializer'];
+
+ $serializerId = $basicSerializerConf['service_id'] ?? "messenger.transport.{$name}.serializer";
+
+ if (($basicSerializerConf['serializer'] ?? null) || ($basicSerializerConf['format'] ?? null) || [] !== $basicSerializerConf['context']) {
+ $serializerDefinition = (new Definition(Serializer::class))
+ ->setArguments([
+ new Reference($basicSerializerConf['serializer'] ?? 'serializer'),
+ $basicSerializerConf['format'] ?? $config['serializer']['symfony_serializer']['format'],
+ $basicSerializerConf['context'] ?: $config['serializer']['symfony_serializer']['context'],
+ ]);
+
+ $container->setDefinition($serializerId, $serializerDefinition);
+ }
+ } elseif (isset($transport['incoming_message_serializer'])) {
+ $incomingSerializerConf = $transport['incoming_message_serializer'];
+
+ $serializerDefinition = (new Definition(IncomingMessageSerializer::class))
+ ->setArguments([
+ $incomingSerializerConf['messageClass'] ?? new Reference($incomingSerializerConf['messageClassResolver']),
+ new Reference($incomingSerializerConf['serializer'] ?? 'serializer'),
+ $incomingSerializerConf['format'] ?? $config['serializer']['symfony_serializer']['format'],
+ $incomingSerializerConf['context'] ?: $config['serializer']['symfony_serializer']['context'],
+ ]);
+
+ $container->setDefinition($serializerId = "messenger.transport.{$name}.serializer", $serializerDefinition);
+ } elseif (isset($transport['outgoing_message_serializer'])) {
+ $outgoingSerializerConf = $transport['outgoing_message_serializer'];
+
+ $serializerDefinition = (new Definition(OutgoingMessageSerializer::class))
+ ->setArguments([
+ new Reference($outgoingSerializerConf['serializer'] ?? 'serializer'),
+ $outgoingSerializerConf['format'] ?? $config['serializer']['symfony_serializer']['format'],
+ $outgoingSerializerConf['context'] ?: $config['serializer']['symfony_serializer']['context'],
+ ]);
+
+ $container->setDefinition($serializerId = "messenger.transport.{$name}.serializer", $serializerDefinition);
+ }
+
+ $serializerId ??= 'messenger.default_serializer';
$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.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer.php
new file mode 100644
index 0000000000000..22fd14d394216
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer.php
@@ -0,0 +1,64 @@
+loadFromExtension('framework', [
+ 'http_method_override' => false,
+ 'serializer' => true,
+ 'messenger' => [
+ 'serializer' => [
+ 'symfony_serializer' => [
+ 'format' => 'xml',
+ 'context' => ['default' => 'context'],
+ ]
+ ],
+ 'transports' => [
+ 'default_serializer' => ['dsn' => 'null://'],
+ 'custom_serializer_short_notation' => [
+ 'dsn' => 'null://',
+ 'serializer' => 'messenger.transport.native_php_serializer',
+ ],
+ 'custom_serializer_long_notation' => [
+ 'dsn' => 'null://',
+ 'serializer' => [
+ 'service_id' => 'messenger.transport.native_php_serializer',
+ ],
+ ],
+ 'symfony_serializer_with_context' => [
+ 'dsn' => 'null://',
+ 'serializer' => [
+ 'format' => 'json',
+ 'context' => ['some' => 'context'],
+ 'serializer' => 'my_fancy_serializer',
+ ],
+ ],
+ 'incoming_message_transport' => [
+ 'dsn' => 'null://',
+ 'incoming_message_serializer' => [
+ 'messageClass' => BarMessage::class,
+ 'format' => 'json',
+ 'context' => ['some' => 'context'],
+ 'serializer' => 'my_fancy_serializer',
+ ],
+ ],
+ 'incoming_message_transport_with_default_serializer' => [
+ 'dsn' => 'null://',
+ 'incoming_message_serializer' => [
+ 'messageClassResolver' => 'some_message_class_resolver_id',
+ ],
+ ],
+ 'outgoing_message_transport' => [
+ 'dsn' => 'null://',
+ 'outgoing_message_serializer' => [
+ 'format' => 'json',
+ 'context' => ['some' => 'context'],
+ 'serializer' => 'my_fancy_serializer',
+ ],
+ ],
+ 'outgoing_message_transport_with_default_serializer' => [
+ 'dsn' => 'null://',
+ 'outgoing_message_serializer' => [],
+ ],
+ ],
+ ],
+]);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_invalid_1.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_invalid_1.php
new file mode 100644
index 0000000000000..869db0f98f26b
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_invalid_1.php
@@ -0,0 +1,15 @@
+loadFromExtension('framework', [
+ 'http_method_override' => false,
+ 'serializer' => true,
+ 'messenger' => [
+ 'transports' => [
+ 'invalid_transport' => [
+ 'dsn' => 'null://',
+ 'serializer' => 'messenger.transport.native_php_serializer',
+ 'outgoing_message_serializer' => []
+ ]
+ ],
+ ],
+]);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_invalid_2.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_invalid_2.php
new file mode 100644
index 0000000000000..b51b50a351c8a
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_invalid_2.php
@@ -0,0 +1,17 @@
+loadFromExtension('framework', [
+ 'http_method_override' => false,
+ 'serializer' => true,
+ 'messenger' => [
+ 'transports' => [
+ 'invalid_transport' => [
+ 'dsn' => 'null://',
+ 'serializer' => [
+ 'service_id' => 'messenger.transport.native_php_serializer',
+ 'format' => 'json'
+ ],
+ ]
+ ],
+ ],
+]);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_invalid_3.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_invalid_3.php
new file mode 100644
index 0000000000000..b4a6a7e16de02
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_invalid_3.php
@@ -0,0 +1,14 @@
+loadFromExtension('framework', [
+ 'http_method_override' => false,
+ 'serializer' => true,
+ 'messenger' => [
+ 'transports' => [
+ 'invalid_transport' => [
+ 'dsn' => 'null://',
+ 'serializer' => [],
+ ]
+ ],
+ ],
+]);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_invalid_4.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_invalid_4.php
new file mode 100644
index 0000000000000..96e5e4d07f531
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_invalid_4.php
@@ -0,0 +1,19 @@
+loadFromExtension('framework', [
+ 'http_method_override' => false,
+ 'serializer' => true,
+ 'messenger' => [
+ 'transports' => [
+ 'invalid_transport' => [
+ 'dsn' => 'null://',
+ 'incoming_message_serializer' => [
+ 'messageClass' => BarMessage::class,
+ 'messageClassResolver' => 'foo',
+ ],
+ ]
+ ],
+ ],
+]);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_invalid_5.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_invalid_5.php
new file mode 100644
index 0000000000000..f46fc375be338
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_serializer_invalid_5.php
@@ -0,0 +1,16 @@
+loadFromExtension('framework', [
+ 'http_method_override' => false,
+ 'serializer' => true,
+ 'messenger' => [
+ 'transports' => [
+ 'invalid_transport' => [
+ 'dsn' => 'null://',
+ 'incoming_message_serializer' => [
+ 'messageClass' => 'foo',
+ ],
+ ]
+ ],
+ ],
+]);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer.xml
new file mode 100644
index 0000000000000..cf583ec809485
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+ context
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ context
+
+
+
+
+
+
+
+ context
+
+
+
+
+
+
+
+
+
+
+
+ context
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_invalid_1.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_invalid_1.xml
new file mode 100644
index 0000000000000..dfd04dc43fef7
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_invalid_1.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_invalid_2.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_invalid_2.xml
new file mode 100644
index 0000000000000..f758f30b1a88c
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_invalid_2.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_invalid_3.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_invalid_3.xml
new file mode 100644
index 0000000000000..4e66c3487f03c
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_invalid_3.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_invalid_4.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_invalid_4.xml
new file mode 100644
index 0000000000000..def75bbcd251b
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_invalid_4.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_invalid_5.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_invalid_5.xml
new file mode 100644
index 0000000000000..0975b13b3bfa7
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_serializer_invalid_5.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer.yml
new file mode 100644
index 0000000000000..eda1c7f12c4ec
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer.yml
@@ -0,0 +1,44 @@
+framework:
+ http_method_override: false
+ serializer: true
+ messenger:
+ serializer:
+ symfony_serializer:
+ format: xml
+ context: {default: context}
+ transports:
+ default_serializer:
+ dsn: 'null://'
+ custom_serializer_short_notation:
+ dsn: 'null://'
+ serializer: 'messenger.transport.native_php_serializer'
+ custom_serializer_long_notation:
+ dsn: 'null://'
+ serializer:
+ service_id: 'messenger.transport.native_php_serializer'
+ symfony_serializer_with_context:
+ dsn: 'null://'
+ serializer:
+ format: 'json'
+ context: {some: context}
+ serializer: 'my_fancy_serializer'
+ incoming_message_transport:
+ dsn: 'null://'
+ incoming_message_serializer:
+ messageClass: Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\BarMessage
+ format: 'json'
+ context: {some: context}
+ serializer: 'my_fancy_serializer'
+ incoming_message_transport_with_default_serializer:
+ dsn: 'null://'
+ incoming_message_serializer:
+ messageClassResolver: 'some_message_class_resolver_id'
+ outgoing_message_transport:
+ dsn: 'null://'
+ outgoing_message_serializer:
+ format: 'json'
+ context: {some: context}
+ serializer: 'my_fancy_serializer'
+ outgoing_message_transport_with_default_serializer:
+ dsn: 'null://'
+ outgoing_message_serializer: ~
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_invalid_1.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_invalid_1.yml
new file mode 100644
index 0000000000000..1d88974672b6f
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_invalid_1.yml
@@ -0,0 +1,9 @@
+framework:
+ http_method_override: false
+ serializer: true
+ messenger:
+ transports:
+ invalid_transport:
+ dsn: 'null://'
+ serializer: 'messenger.transport.native_php_serializer'
+ outgoing_message_serializer: ~
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_invalid_2.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_invalid_2.yml
new file mode 100644
index 0000000000000..2086945145672
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_invalid_2.yml
@@ -0,0 +1,10 @@
+framework:
+ http_method_override: false
+ serializer: true
+ messenger:
+ transports:
+ invalid_transport:
+ dsn: 'null://'
+ serializer:
+ service_id: 'messenger.transport.native_php_serializer'
+ format: json
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_invalid_3.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_invalid_3.yml
new file mode 100644
index 0000000000000..1c42ed1e16704
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_invalid_3.yml
@@ -0,0 +1,8 @@
+framework:
+ http_method_override: false
+ serializer: true
+ messenger:
+ transports:
+ invalid_transport:
+ dsn: 'null://'
+ serializer: ~
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_invalid_4.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_invalid_4.yml
new file mode 100644
index 0000000000000..5096657148ff8
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_invalid_4.yml
@@ -0,0 +1,10 @@
+framework:
+ http_method_override: false
+ serializer: true
+ messenger:
+ transports:
+ invalid_transport:
+ dsn: 'null://'
+ incoming_message_serializer:
+ messageClass: Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\BarMessage
+ messageClassResolver: foo
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_invalid_5.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_invalid_5.yml
new file mode 100644
index 0000000000000..44363a712bfde
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_serializer_invalid_5.yml
@@ -0,0 +1,9 @@
+framework:
+ http_method_override: false
+ serializer: true
+ messenger:
+ transports:
+ invalid_transport:
+ dsn: 'null://'
+ incoming_message_serializer:
+ messageClass: foo
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
index e3416357c162b..d224ab7f18bc2 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
@@ -18,6 +18,7 @@
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddAnnotationsCachedReaderPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkExtension;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
+use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\BarMessage;
use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\DummyMessage;
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
use Symfony\Bundle\FullStack;
@@ -57,6 +58,9 @@
use Symfony\Component\HttpClient\ScopingHttpClient;
use Symfony\Component\HttpKernel\DependencyInjection\LoggerPass;
use Symfony\Component\HttpKernel\Fragment\FragmentUriGeneratorInterface;
+use Symfony\Component\Messenger\Transport\Serialization\IncomingMessageSerializer;
+use Symfony\Component\Messenger\Transport\Serialization\OutgoingMessageSerializer;
+use Symfony\Component\Messenger\Transport\Serialization\Serializer as MessengerTransportSerializer;
use Symfony\Component\Messenger\Transport\TransportFactory;
use Symfony\Component\Notifier\ChatterInterface;
use Symfony\Component\Notifier\TexterInterface;
@@ -1083,6 +1087,107 @@ public function testMessengerWithDisabledResetOnMessage()
$this->createContainerFromFile('messenger_with_disabled_reset_on_message');
}
+ public function testMessengerTransportSerializerConfigurations()
+ {
+ $container = $this->createContainerFromFile('messenger_transport_serializer');
+
+ $transportDefinition = $container->getDefinition('messenger.transport.default_serializer');
+ $this->assertEquals(new Reference('messenger.default_serializer'), $transportDefinition->getArguments()[2]);
+
+ $transportDefinition = $container->getDefinition('messenger.transport.custom_serializer_short_notation');
+ $this->assertEquals(new Reference('messenger.transport.native_php_serializer'), $transportDefinition->getArguments()[2]);
+
+ $transportDefinition = $container->getDefinition('messenger.transport.custom_serializer_long_notation');
+ $this->assertEquals(new Reference('messenger.transport.native_php_serializer'), $transportDefinition->getArguments()[2]);
+
+ $transportDefinition = $container->getDefinition('messenger.transport.symfony_serializer_with_context');
+ $this->assertEquals(new Reference($serializerId = 'messenger.transport.symfony_serializer_with_context.serializer'), $transportDefinition->getArguments()[2]);
+ $serializerDefinition = $container->getDefinition($serializerId);
+ self::assertSame(MessengerTransportSerializer::class, $serializerDefinition->getClass());
+ self::assertEquals(
+ [
+ new Reference('my_fancy_serializer'),
+ 'json',
+ ['some' => 'context'],
+ ],
+ $serializerDefinition->getArguments()
+ );
+
+ $transportDefinition = $container->getDefinition('messenger.transport.incoming_message_transport');
+ $this->assertEquals(new Reference($serializerId = 'messenger.transport.incoming_message_transport.serializer'), $transportDefinition->getArguments()[2]);
+ $serializerDefinition = $container->getDefinition($serializerId);
+ self::assertSame(IncomingMessageSerializer::class, $serializerDefinition->getClass());
+ self::assertEquals(
+ [
+ BarMessage::class,
+ new Reference('my_fancy_serializer'),
+ 'json',
+ ['some' => 'context'],
+ ],
+ $serializerDefinition->getArguments()
+ );
+
+ $transportDefinition = $container->getDefinition('messenger.transport.incoming_message_transport_with_default_serializer');
+ $this->assertEquals(new Reference($serializerId = 'messenger.transport.incoming_message_transport_with_default_serializer.serializer'), $transportDefinition->getArguments()[2]);
+ $serializerDefinition = $container->getDefinition($serializerId);
+ self::assertSame(IncomingMessageSerializer::class, $serializerDefinition->getClass());
+ self::assertEquals(
+ [
+ new Reference('some_message_class_resolver_id'),
+ new Reference('serializer'),
+ 'xml',
+ ['default' => 'context'],
+ ],
+ $serializerDefinition->getArguments()
+ );
+
+ $transportDefinition = $container->getDefinition('messenger.transport.outgoing_message_transport');
+ $this->assertEquals(new Reference($serializerId = 'messenger.transport.outgoing_message_transport.serializer'), $transportDefinition->getArguments()[2]);
+ $serializerDefinition = $container->getDefinition($serializerId);
+ self::assertSame(OutgoingMessageSerializer::class, $serializerDefinition->getClass());
+ self::assertEquals(
+ [
+ new Reference('my_fancy_serializer'),
+ 'json',
+ ['some' => 'context'],
+ ],
+ $serializerDefinition->getArguments()
+ );
+
+ $transportDefinition = $container->getDefinition('messenger.transport.outgoing_message_transport_with_default_serializer');
+ $this->assertEquals(new Reference($serializerId = 'messenger.transport.outgoing_message_transport_with_default_serializer.serializer'), $transportDefinition->getArguments()[2]);
+ $serializerDefinition = $container->getDefinition($serializerId);
+ self::assertSame(OutgoingMessageSerializer::class, $serializerDefinition->getClass());
+ self::assertEquals(
+ [
+ new Reference('serializer'),
+ 'xml',
+ ['default' => 'context'],
+ ],
+ $serializerDefinition->getArguments()
+ );
+ }
+
+ /**
+ * @dataProvider invalidMessengerTransportSerializerConfigurationsProvider
+ */
+ public function testInvalidMessengerTransportSerializerConfigurations(string $configFile, string $errorMessage)
+ {
+ $this->expectException(InvalidConfigurationException::class);
+ $this->expectExceptionMessage($errorMessage);
+
+ $this->createContainerFromFile($configFile);
+ }
+
+ public function invalidMessengerTransportSerializerConfigurationsProvider(): iterable
+ {
+ yield ['messenger_transport_serializer_invalid_1', 'Only one of "serializer", "incoming_message_serializer" and "outgoing_message_serializer" could be used'];
+ yield ['messenger_transport_serializer_invalid_2', 'Either "service_id" OR at least one of "format" or "context" or "serializer" should be provided.'];
+ yield ['messenger_transport_serializer_invalid_3', 'Either "service_id" OR at least one of "format" or "context" or "serializer" should be provided.'];
+ yield ['messenger_transport_serializer_invalid_4', 'A message class OR a message class resolver should be provided.'];
+ yield ['messenger_transport_serializer_invalid_5', 'The "messageClass" should be a valid class.'];
+ }
+
public function testTranslator()
{
$container = $this->createContainerFromFile('full');
diff --git a/src/Symfony/Component/Messenger/Transport/Serialization/IncomingMessageClassResolverInterface.php b/src/Symfony/Component/Messenger/Transport/Serialization/IncomingMessageClassResolverInterface.php
new file mode 100644
index 0000000000000..7ef0db2d1ce0d
--- /dev/null
+++ b/src/Symfony/Component/Messenger/Transport/Serialization/IncomingMessageClassResolverInterface.php
@@ -0,0 +1,20 @@
+
+ *
+ * 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;
+
+interface IncomingMessageClassResolverInterface
+{
+ /**
+ * @return class-string
+ */
+ public function __invoke(array $encodedEnvelope): string;
+}
diff --git a/src/Symfony/Component/Messenger/Transport/Serialization/IncomingMessageSerializer.php b/src/Symfony/Component/Messenger/Transport/Serialization/IncomingMessageSerializer.php
new file mode 100644
index 0000000000000..069c88559ea70
--- /dev/null
+++ b/src/Symfony/Component/Messenger/Transport/Serialization/IncomingMessageSerializer.php
@@ -0,0 +1,42 @@
+
+ *
+ * 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;
+
+use Symfony\Component\Messenger\Envelope;
+use Symfony\Component\Serializer\SerializerInterface as SymfonySerializerInterface;
+
+final class IncomingMessageSerializer implements SerializerInterface
+{
+ private Serializer $decorated;
+
+ public function __construct(private readonly IncomingMessageClassResolverInterface|string $messageClass, SymfonySerializerInterface $serializer, string $format, array $context)
+ {
+ $this->decorated = new Serializer($serializer, $format, $context);
+ }
+
+ public function decode(array $encodedEnvelope): Envelope
+ {
+ $encodedEnvelope['headers']['type'] ??= $this->resolveType($encodedEnvelope);
+
+ return $this->decorated->decode($encodedEnvelope);
+ }
+
+ public function encode(Envelope $envelope): array
+ {
+ return $this->decorated->encode($envelope);
+ }
+
+ private function resolveType(array $encodedEnvelope): string
+ {
+ return \is_string($this->messageClass) ? $this->messageClass : ($this->messageClass)($encodedEnvelope);
+ }
+}
diff --git a/src/Symfony/Component/Messenger/Transport/Serialization/OutgoingMessageSerializer.php b/src/Symfony/Component/Messenger/Transport/Serialization/OutgoingMessageSerializer.php
new file mode 100644
index 0000000000000..7b01e593a18bb
--- /dev/null
+++ b/src/Symfony/Component/Messenger/Transport/Serialization/OutgoingMessageSerializer.php
@@ -0,0 +1,39 @@
+
+ *
+ * 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;
+
+use Symfony\Component\Messenger\Envelope;
+use Symfony\Component\Serializer\SerializerInterface as SymfonySerializerInterface;
+
+final class OutgoingMessageSerializer implements SerializerInterface
+{
+ private Serializer $decorated;
+
+ public function __construct(SymfonySerializerInterface $serializer, string $format, array $context)
+ {
+ $this->decorated = new Serializer($serializer, $format, $context);
+ }
+
+ public function decode(array $encodedEnvelope): Envelope
+ {
+ throw new \LogicException(sprintf('Cannot use "%s" to decode message.', __CLASS__));
+ }
+
+ public function encode(Envelope $envelope): array
+ {
+ $encode = $this->decorated->encode(Envelope::wrap($envelope->getMessage()));
+
+ unset($encode['headers']['type']);
+
+ return $encode;
+ }
+}