feature #28270 [Messenger] Uses Symfony Serializer by default for envelope items (sroze)

This PR was merged into the 4.2-dev branch.

Discussion
----------

[Messenger] Uses Symfony Serializer by default for envelope items

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | yes
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #28164
| License       | MIT
| Doc PR        | ø

The original approach was to use `serialize`/`unserialize` for envelope items. It turns out it has limitations (see #28247) and reduces the compatibility with 3rd party systems (see #28164). This pull-request changes the existing mechanism by using Symfony Serializer by default.

It keeps the `serialize`/`unserialize` mechanism to allow users of the experimental component to keep using it in 4.2 and allow to have a non-disruptive upgrade to 4.2.

Commits
-------

9b575ab263 Uses Symfony Serializer by default for envelope items
This commit is contained in:
Fabien Potencier 2018-09-04 10:43:45 +02:00
commit 5a63f19bad
2 changed files with 43 additions and 12 deletions

View File

@ -80,15 +80,17 @@ class SerializerTest extends TestCase
$this->assertSame($message, $decoded->getMessage());
}
public function testEncodedWithSerializationConfiguration()
public function testEncodedWithSymfonySerializerForItems()
{
$serializer = new Serializer(
new SerializerComponent\Serializer(array(new ObjectNormalizer()), array('json' => new JsonEncoder()))
new SerializerComponent\Serializer(array(new ObjectNormalizer()), array('json' => new JsonEncoder())),
'json',
array()
);
$envelope = Envelope::wrap(new DummyMessage('Hello'))
->with(new SerializerConfiguration(array(ObjectNormalizer::GROUPS => array('foo'))))
->with(new ValidationConfiguration(array('foo', 'bar')))
->with($serializerConfiguration = new SerializerConfiguration(array(ObjectNormalizer::GROUPS => array('foo'))))
->with($validationConfiguration = new ValidationConfiguration(array('foo', 'bar')))
;
$encoded = $serializer->encode($envelope);
@ -96,8 +98,12 @@ class SerializerTest extends TestCase
$this->assertArrayHasKey('body', $encoded);
$this->assertArrayHasKey('headers', $encoded);
$this->assertArrayHasKey('type', $encoded['headers']);
$this->assertEquals(DummyMessage::class, $encoded['headers']['type']);
$this->assertArrayHasKey('X-Message-Envelope-Items', $encoded['headers']);
$this->assertSame('a:2:{s:75:"Symfony\Component\Messenger\Transport\Serialization\SerializerConfiguration";O:75:"Symfony\Component\Messenger\Transport\Serialization\SerializerConfiguration":1:{s:84:"'."\0".'Symfony\Component\Messenger\Transport\Serialization\SerializerConfiguration'."\0".'context";a:1:{s:6:"groups";a:1:{i:0;s:3:"foo";}}}s:76:"Symfony\Component\Messenger\Middleware\Configuration\ValidationConfiguration";O:76:"Symfony\Component\Messenger\Middleware\Configuration\ValidationConfiguration":1:{s:84:"'."\0".'Symfony\Component\Messenger\Middleware\Configuration\ValidationConfiguration'."\0".'groups";a:2:{i:0;s:3:"foo";i:1;s:3:"bar";}}}', $encoded['headers']['X-Message-Envelope-Items']);
$this->assertArrayHasKey('X-Message-Envelope-Symfony\Component\Messenger\Transport\Serialization\SerializerConfiguration', $encoded['headers']);
$this->assertArrayHasKey('X-Message-Envelope-Symfony\Component\Messenger\Middleware\Configuration\ValidationConfiguration', $encoded['headers']);
$decoded = $serializer->decode($encoded);
$this->assertEquals($serializerConfiguration, $decoded->get(SerializerConfiguration::class));
$this->assertEquals($validationConfiguration, $decoded->get(ValidationConfiguration::class));
}
}

View File

@ -43,7 +43,7 @@ class Serializer implements DecoderInterface, EncoderInterface
throw new \InvalidArgumentException('Encoded envelope does not have a `type` header.');
}
$envelopeItems = isset($encodedEnvelope['headers']['X-Message-Envelope-Items']) ? unserialize($encodedEnvelope['headers']['X-Message-Envelope-Items']) : array();
$envelopeItems = $this->decodeEnvelopeItems($encodedEnvelope);
$context = $this->context;
/** @var SerializerConfiguration|null $serializerConfig */
@ -67,14 +67,39 @@ class Serializer implements DecoderInterface, EncoderInterface
$context = $serializerConfig->getContext() + $context;
}
$headers = array('type' => \get_class($envelope->getMessage()));
if ($configurations = $envelope->all()) {
$headers['X-Message-Envelope-Items'] = serialize($configurations);
}
$headers = array('type' => \get_class($envelope->getMessage())) + $this->encodeEnvelopeItems($envelope);
return array(
'body' => $this->serializer->serialize($envelope->getMessage(), $this->format, $context),
'headers' => $headers,
);
}
private function decodeEnvelopeItems($encodedEnvelope)
{
$items = array();
foreach ($encodedEnvelope['headers'] as $name => $value) {
if (0 !== strpos($name, $prefix = 'X-Message-Envelope-')) {
continue;
}
$items[] = $this->serializer->deserialize($value, substr($name, \strlen($prefix)), $this->format, $this->context);
}
return $items;
}
private function encodeEnvelopeItems(Envelope $envelope)
{
if (!$configurations = $envelope->all()) {
return array();
}
$headers = array();
foreach ($configurations as $configuration) {
$headers['X-Message-Envelope-'.\get_class($configuration)] = $this->serializer->serialize($configuration, $this->format, $this->context);
}
return $headers;
}
}