Skip to content
Permalink
Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
143 lines (118 sloc) 4.92 KB
<?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\Transport\Serialization;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\InvalidArgumentException;
use Symfony\Component\Messenger\Exception\LogicException;
use Symfony\Component\Messenger\Exception\MessageDecodingFailedException;
use Symfony\Component\Messenger\Stamp\SerializerStamp;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer as SymfonySerializer;
use Symfony\Component\Serializer\SerializerInterface as SymfonySerializerInterface;
/**
* @author Samuel Roze <samuel.roze@gmail.com>
*
* @experimental in 4.2
*/
class Serializer implements SerializerInterface
{
private const STAMP_HEADER_PREFIX = 'X-Message-Stamp-';
private $serializer;
private $format;
private $context;
public function __construct(SymfonySerializerInterface $serializer = null, string $format = 'json', array $context = [])
{
$this->serializer = $serializer ?? self::create()->serializer;
$this->format = $format;
$this->context = $context;
}
public static function create(): self
{
if (!class_exists(SymfonySerializer::class)) {
throw new LogicException(sprintf('The default Messenger Serializer requires Symfony\'s Serializer component. Try running "composer require symfony/serializer".'));
}
$encoders = [new XmlEncoder(), new JsonEncoder()];
$normalizers = [new ArrayDenormalizer(), new ObjectNormalizer()];
$serializer = new SymfonySerializer($normalizers, $encoders);
return new self($serializer);
}
/**
* {@inheritdoc}
*/
public function decode(array $encodedEnvelope): Envelope
{
if (empty($encodedEnvelope['body']) || empty($encodedEnvelope['headers'])) {
throw new InvalidArgumentException('Encoded envelope should have at least a "body" and some "headers".');
}
if (empty($encodedEnvelope['headers']['type'])) {
throw new InvalidArgumentException('Encoded envelope does not have a "type" header.');
}
$stamps = $this->decodeStamps($encodedEnvelope);
$context = $this->context;
if (isset($stamps[SerializerStamp::class])) {
$context = end($stamps[SerializerStamp::class])->getContext() + $context;
}
try {
$message = $this->serializer->deserialize($encodedEnvelope['body'], $encodedEnvelope['headers']['type'], $this->format, $context);
} catch (UnexpectedValueException $e) {
throw new MessageDecodingFailedException(sprintf('Could not decode message: %s.', $e->getMessage()), $e->getCode(), $e);
}
return new Envelope($message, ...$stamps);
}
/**
* {@inheritdoc}
*/
public function encode(Envelope $envelope): array
{
$context = $this->context;
/** @var SerializerStamp|null $serializerStamp */
if ($serializerStamp = $envelope->last(SerializerStamp::class)) {
$context = $serializerStamp->getContext() + $context;
}
$headers = ['type' => \get_class($envelope->getMessage())] + $this->encodeStamps($envelope);
return [
'body' => $this->serializer->serialize($envelope->getMessage(), $this->format, $context),
'headers' => $headers,
];
}
private function decodeStamps(array $encodedEnvelope): array
{
$stamps = [];
foreach ($encodedEnvelope['headers'] as $name => $value) {
if (0 !== strpos($name, self::STAMP_HEADER_PREFIX)) {
continue;
}
try {
$stamps[] = $this->serializer->deserialize($value, substr($name, \strlen(self::STAMP_HEADER_PREFIX)).'[]', $this->format, $this->context);
} catch (UnexpectedValueException $e) {
throw new MessageDecodingFailedException(sprintf('Could not decode stamp: %s.', $e->getMessage()), $e->getCode(), $e);
}
}
if ($stamps) {
$stamps = array_merge(...$stamps);
}
return $stamps;
}
private function encodeStamps(Envelope $envelope): array
{
if (!$allStamps = $envelope->all()) {
return [];
}
$headers = [];
foreach ($allStamps as $class => $stamps) {
$headers[self::STAMP_HEADER_PREFIX.$class] = $this->serializer->serialize($stamps, $this->format, $this->context);
}
return $headers;
}
}
You can’t perform that action at this time.