Home > Blockchain >  Symfony messenger - serialize objects inside message
Symfony messenger - serialize objects inside message

Time:04-15

Hi I have applications that is dispatching commands(messages) to Amazon SQS queues. I have working environment and my commands are in the queue, but in the wrong format like this:

{ "Messages": [ { "MessageId": "f3373e0d-b47e-2a46-51d8-38dc1ee8f07e", "ReceiptHandle": "dzpfgjsnrkwzmzzvzvddepxfpmxwipviybehoedxeolvbndunmceerozsanhwennjvgeunbsfxfxrrywrlkpeuifcnggnslzfgpkilnrwnlyegkcmlaowvcikxhsisujptanjrboedurezuzihngpfmsyxxzmtqghqyrfyycthxuamqnxblprvbbo", "MD5OfBody": "6a69c6c1e53718f891a409e5a9ba98a4", "Body": "O:36:\"Symfony\\Component\\Messenger\\Envelope\":2:{s:44:\"\0Symfony\\Component\\Messenger\\Envelope\0stamps\";a:1:{s:46:\"Symfony\\Component\\Messenger\\Stamp\\BusNameStamp\";a:1:{i:0;O:46:\"Symfony\\Component\\Messenger\\Stamp\\BusNameStamp\":1:{s:55:\"\0Symfony\\Component\\Messenger\\Stamp\\BusNameStamp\0busName\";s:21:\"messenger.bus.default\";}}}s:45:\"\0Symfony\\Component\\Messenger\\Envelope\0message\";O:29:\"App\\Message\\CreatePostCommand\":1:{s:17:\"\0*\0postDataObject\";O:29:\"App\\DataObject\\PostDataObject\":5:{s:5:\"title\";s:11:\"Lorem ipsum\";s:7:\"excerpt\";s:27:\"Lorem ipsum dolor sit amet.\";s:7:\"content\";s:495:\"Donec laoreet maximus lacus, nec lacinia risus rutrum vitae. Morbi tortor sapien, ornare in congue ac, aliquam quis felis. Pellentesque venenatis, elit eget vehicula viverra, elit lacus congue ante, et accumsan est arcu vitae purus. Aliquam erat volutpat. Nullam rhoncus risus augue, ut rhoncus leo sollicitudin sed. Maecenas fringilla, metus pretium tristique sodales, sem ante condimentum massa, a facilisis ligula lacus quis purus. Vestibulum pharetra rutrum velit, in rutrum mi mollis vitae.\";s:6:\"author\";s:14:\"Bartosz Belski\";s:12:\"published_at\";N;}}}", "Attributes": { "SenderId": "AIDAIT2UOQQY3AUEKVGXU", "SentTimestamp": "1649947456026" } } ] }

I suspect that this is fault of serialization. I want to store it as a json inside the queue. But I have no idea how to accomplish this.

My Command(message):

final class CreatePostCommand
{
    protected PostDataObject $postDataObject;

    public function __construct(PostDataObject $postDataObject)
    {
        $this->postDataObject = $postDataObject;
    }

    public function getPostDataObject(): PostDataObject
    {
        return $this->postDataObject;
    }

    public function setPostDataObject(PostDataObject $postDataObject): self
    {
        $this->postDataObject = $postDataObject;

        return $this;
    }
}

My PostDataObject:

class PostDataObject extends DataObject
{
    public $title;

    public $excerpt;

    public $content;

    public $author;

    public $published_at;
}

CodePudding user response:

There are two methods to implement __serialize and __unserialize. Using them convert to/from json in format that you want:

final class CreatePostCommand
{
    protected PostDataObject $postDataObject;

    public function __serialize(): array
    {
        return ['title' => $this->postDataObject->title, 'excerpt' => $this->postDataObject->excerpt, ...];
    }

    public function __deserialize(array $data): void
    {
        $this->postDataObject->title = $data['title'];
        $this->postDataObject->excerpt = $data['excerpt'];
        ...
    }
}

CodePudding user response:

my solution was a bit different than what @Justinas proposed. I created my own serializer for symfony messenger like in this tutorial:

My code:

namespace App\Message\Serializers;

use App\DataObject\PostDataObject;
use App\Message\CreatePostCommand;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;

class JsonDataObjectCommandSerializer implements SerializerInterface
{
    private \Symfony\Component\Serializer\SerializerInterface $serializer;

    public function __construct(\Symfony\Component\Serializer\SerializerInterface $serializer)
    {
        $this->serializer = $serializer;
    }

    public function decode(array $encodedEnvelope): Envelope
    {
        $body = $encodedEnvelope['body'];
        $headers = $encodedEnvelope['headers'];
        $data = json_decode($body, true);
        $message = new CreatePostCommand(new PostDataObject($data));
        $stamps = [];
        if (isset($headers['stamps'])) {
            $stamps = json_decode($headers['stamps']);
        }
        dump($data, $message, $stamps);
        return new Envelope($message, $stamps ?? []);
    }

    public function encode(Envelope $envelope): array
    {
        $message = $envelope->getMessage();
        if ($message instanceof CreatePostCommand) {
            $data = $message->getPostDataObject()->toArray();
        } else {
            throw new \Exception('Unsupported message class');
        }
        $allStamps = [];
        foreach ($envelope->all() as $stamps) {
            $allStamps = array_merge($allStamps, $stamps);
        }

        return [
            'body' => json_encode($data),
            'headers' => [
                'stamps' => $this->serializer->serialize($allStamps, 'json')
            ]
        ];
    }
}
  • Related