diff --git a/pkg/enqueue/Client/MessageProducer.php b/pkg/enqueue/Client/MessageProducer.php index 820ae0d2d..39f64d397 100644 --- a/pkg/enqueue/Client/MessageProducer.php +++ b/pkg/enqueue/Client/MessageProducer.php @@ -62,9 +62,6 @@ private function prepareBody(Message $message) $contentType = $contentType ?: 'text/plain'; $body = (string) $body; } elseif (is_array($body)) { - $body = $message->getBody(); - $contentType = $message->getContentType(); - if ($contentType && $contentType !== 'application/json') { throw new \LogicException(sprintf('Content type "application/json" only allowed when body is array')); } @@ -79,11 +76,18 @@ private function prepareBody(Message $message) } }); + $contentType = 'application/json'; + $body = JSON::encode($body); + } elseif ($body instanceof \JsonSerializable) { + if ($contentType && $contentType !== 'application/json') { + throw new \LogicException(sprintf('Content type "application/json" only allowed when body is array')); + } + $contentType = 'application/json'; $body = JSON::encode($body); } else { throw new \InvalidArgumentException(sprintf( - 'The message\'s body must be either null, scalar or array. Got: %s', + 'The message\'s body must be either null, scalar, array or object (implements \JsonSerializable). Got: %s', is_object($body) ? get_class($body) : gettype($body) )); } diff --git a/pkg/enqueue/Tests/Client/MessageProducerTest.php b/pkg/enqueue/Tests/Client/MessageProducerTest.php index b85aa1b98..cab846c59 100644 --- a/pkg/enqueue/Tests/Client/MessageProducerTest.php +++ b/pkg/enqueue/Tests/Client/MessageProducerTest.php @@ -298,7 +298,7 @@ public function testShouldThrowExceptionIfBodyIsObjectOnSend() $producer = new MessageProducer($driver); $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The message\'s body must be either null, scalar or array. Got: stdClass'); + $this->expectExceptionMessage('The message\'s body must be either null, scalar, array or object (implements \JsonSerializable). Got: stdClass'); $producer->send('topic', new \stdClass()); } @@ -339,6 +339,66 @@ public function testShouldThrowExceptionIfBodyIsArrayWithObjectsInSubArraysInsid $producer->send($queue, ['foo' => ['bar' => new \stdClass()]]); } + public function testShouldSendJsonSerializableObjectAsJsonString() + { + $object = new JsonSerializableObject(); + + $driver = $this->createDriverStub(); + $driver + ->expects($this->once()) + ->method('sendToRouter') + ->willReturnCallback(function (Message $message) { + self::assertSame('{"foo":"fooVal"}', $message->getBody()); + self::assertSame('application/json', $message->getContentType()); + }) + ; + + $producer = new MessageProducer($driver); + $producer->send('topic', $object); + } + + public function testShouldSendMessageJsonSerializableBodyAsJsonString() + { + $object = new JsonSerializableObject(); + + $message = new Message(); + $message->setBody($object); + + $driver = $this->createDriverStub(); + $driver + ->expects($this->once()) + ->method('sendToRouter') + ->willReturnCallback(function (Message $message) { + self::assertSame('{"foo":"fooVal"}', $message->getBody()); + self::assertSame('application/json', $message->getContentType()); + }) + ; + + $producer = new MessageProducer($driver); + $producer->send('topic', $message); + } + + public function testThrowIfNotApplicationJsonContentTypeSetWithJsonSerializableBody() + { + $object = new JsonSerializableObject(); + + $message = new Message(); + $message->setBody($object); + $message->setContentType('foo/bar'); + + $driver = $this->createDriverStub(); + $driver + ->expects($this->never()) + ->method('sendToRouter') + ; + + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('Content type "application/json" only allowed when body is array'); + + $producer = new MessageProducer($driver); + $producer->send('topic', $message); + } + /** * @return \PHPUnit_Framework_MockObject_MockObject|DriverInterface */ @@ -347,3 +407,11 @@ protected function createDriverStub() return $this->createMock(DriverInterface::class); } } + +class JsonSerializableObject implements \JsonSerializable +{ + public function jsonSerialize() + { + return ['foo' => 'fooVal']; + } +};