From da7a07145b838d00ced8abfee969f183361e7e46 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 20 Oct 2025 21:27:54 +0300 Subject: [PATCH] Fix send message response object --- src/Api.php | 2 +- src/ModelFactory.php | 31 ++++++++++++++- tests/ApiTest.php | 77 +++++++++++++++++++++++++------------- tests/ModelFactoryTest.php | 30 +++++++++++++++ 4 files changed, 113 insertions(+), 27 deletions(-) diff --git a/src/Api.php b/src/Api.php index 87e16a3..18718d5 100644 --- a/src/Api.php +++ b/src/Api.php @@ -363,7 +363,7 @@ class Api $this->buildNewMessageBody($text, $attachments, $format, $link, $notify), ); - return $this->modelFactory->createMessage($response['message']); + return $this->modelFactory->createMessageFromSendResponse($response); } /** diff --git a/src/ModelFactory.php b/src/ModelFactory.php index 1da8031..79ffc2f 100644 --- a/src/ModelFactory.php +++ b/src/ModelFactory.php @@ -128,6 +128,33 @@ class ModelFactory : []; } + /** + * Creates a Message from the specific response structure of the sendMessage endpoint. + * + * @param array $data The raw response from the client. + * + * @return Message + * @throws ReflectionException + */ + public function createMessageFromSendResponse(array $data): Message + { + $messageData = $data['message']; + + $topLevelData = [ + 'chat_id' => $data['chat_id'] ?? null, + 'recipient_id' => $data['recipient_id'] ?? null, + 'message_id' => $data['message_id'] ?? null, + ]; + $messageData = array_merge($messageData, array_filter($topLevelData, fn($value) => $value !== null)); + + if (isset($messageData['message']) && is_array($messageData['message'])) { + $messageData['body'] = $messageData['message']; + unset($messageData['message']); + } + + return $this->createMessage($messageData); + } + /** * Message. * @@ -267,7 +294,9 @@ class ModelFactory InlineButtonType::RequestGeoLocation => RequestGeoLocationButton::fromArray($data), InlineButtonType::Chat => ChatButton::fromArray($data), InlineButtonType::OpenApp => OpenAppButton::fromArray($data), - default => throw new LogicException('Unknown or unsupported inline button type: ' . ($data['type'] ?? 'none')), + default => throw new LogicException( + 'Unknown or unsupported inline button type: ' . ($data['type'] ?? 'none') + ), }; } diff --git a/tests/ApiTest.php b/tests/ApiTest.php index ce6cd52..2b70d47 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -336,7 +336,7 @@ final class ApiTest extends TestCase $apiResponse = [ 'message' => [ 'timestamp' => time(), - 'body' => ['mid' => 'mid.456.xyz', 'seq' => 101, 'text' => $text], + 'message' => ['mid' => 'mid.456.xyz', 'seq' => 101, 'text' => $text], 'recipient' => ['chat_type' => 'dialog', 'user_id' => 123, 'chat_id' => null], 'sender' => [ 'user_id' => 123, @@ -348,9 +348,18 @@ final class ApiTest extends TestCase ], 'url' => 'https://max.ru/message/123', ], + 'chat_id' => 20414985, + 'recipient_id' => 4328369, + 'message_id' => 'mid.456.xyz', ]; - $expectedMessageObject = Message::fromArray($apiResponse['message']); + $finalMessageData = $apiResponse['message']; + $finalMessageData['body'] = $finalMessageData['message']; + unset($finalMessageData['message']); + $finalMessageData['chat_id'] = $apiResponse['chat_id']; + $finalMessageData['recipient_id'] = $apiResponse['recipient_id']; + $finalMessageData['message_id'] = $apiResponse['message_id']; + $expectedMessageObject = Message::fromArray($finalMessageData); $this->clientMock ->expects($this->once()) @@ -360,8 +369,8 @@ final class ApiTest extends TestCase $this->modelFactoryMock ->expects($this->once()) - ->method('createMessage') - ->with($apiResponse['message']) + ->method('createMessageFromSendResponse') + ->with($apiResponse) ->willReturn($expectedMessageObject); $result = $this->api->sendMessage( @@ -416,12 +425,17 @@ final class ApiTest extends TestCase $apiResponse = [ 'message' => [ 'timestamp' => time(), - 'body' => ['mid' => 'mid.test.123', 'seq' => 1, 'text' => $text], + 'message' => ['mid' => 'mid.test.123', 'seq' => 1, 'text' => $text], 'recipient' => ['chat_type' => 'dialog', 'user_id' => 123, 'chat_id' => null], - ] + ], + 'message_id' => 'mid.test.123', ]; - $expectedMessageObject = Message::fromArray($apiResponse['message']); + $finalMessageData = $apiResponse['message']; + $finalMessageData['body'] = $finalMessageData['message']; + unset($finalMessageData['message']); + $finalMessageData['message_id'] = $apiResponse['message_id']; + $expectedMessageObject = Message::fromArray($finalMessageData); $this->clientMock ->expects($this->once()) @@ -436,8 +450,8 @@ final class ApiTest extends TestCase $this->modelFactoryMock ->expects($this->once()) - ->method('createMessage') - ->with($apiResponse['message']) + ->method('createMessageFromSendResponse') + ->with($apiResponse) ->willReturn($expectedMessageObject); $result = $this->api->sendMessage( @@ -803,11 +817,15 @@ final class ApiTest extends TestCase $apiResponse = [ 'message' => [ 'timestamp' => time(), - 'body' => ['mid' => 'mid.sticker.1', 'seq' => 10], + 'message' => ['mid' => 'mid.sticker.1', 'seq' => 10], 'recipient' => ['chat_type' => 'dialog', 'user_id' => $chatId], ] ]; - $expectedMessageObject = Message::fromArray($apiResponse['message']); + + $finalMessageData = $apiResponse['message']; + $finalMessageData['body'] = $finalMessageData['message']; + unset($finalMessageData['message']); + $expectedMessageObject = Message::fromArray($finalMessageData); $this->clientMock->expects($this->once()) ->method('request') @@ -815,8 +833,8 @@ final class ApiTest extends TestCase ->willReturn($apiResponse); $this->modelFactoryMock->expects($this->once()) - ->method('createMessage') - ->with($apiResponse['message']) + ->method('createMessageFromSendResponse') + ->with($apiResponse) ->willReturn($expectedMessageObject); $result = $this->api->sendMessage(chatId: $chatId, attachments: [$stickerRequest]); @@ -849,11 +867,14 @@ final class ApiTest extends TestCase $apiResponse = [ 'message' => [ 'timestamp' => time(), - 'body' => ['mid' => 'mid.contact.1', 'seq' => 11], + 'message' => ['mid' => 'mid.contact.1', 'seq' => 11], 'recipient' => ['chat_type' => 'dialog', 'user_id' => $chatId], ] ]; - $expectedMessageObject = Message::fromArray($apiResponse['message']); + $finalMessageData = $apiResponse['message']; + $finalMessageData['body'] = $finalMessageData['message']; + unset($finalMessageData['message']); + $expectedMessageObject = Message::fromArray($finalMessageData); $this->clientMock->expects($this->once()) ->method('request') @@ -861,8 +882,8 @@ final class ApiTest extends TestCase ->willReturn($apiResponse); $this->modelFactoryMock->expects($this->once()) - ->method('createMessage') - ->with($apiResponse['message']) + ->method('createMessageFromSendResponse') + ->with($apiResponse) ->willReturn($expectedMessageObject); $result = $this->api->sendMessage(chatId: $chatId, attachments: [$contactRequest]); @@ -895,11 +916,14 @@ final class ApiTest extends TestCase $apiResponse = [ 'message' => [ 'timestamp' => time(), - 'body' => ['mid' => 'mid.location.1', 'seq' => 12], + 'message' => ['mid' => 'mid.location.1', 'seq' => 12], 'recipient' => ['chat_type' => 'dialog', 'user_id' => $chatId], ] ]; - $expectedMessageObject = Message::fromArray($apiResponse['message']); + $finalMessageData = $apiResponse['message']; + $finalMessageData['body'] = $finalMessageData['message']; + unset($finalMessageData['message']); + $expectedMessageObject = Message::fromArray($finalMessageData); $this->clientMock->expects($this->once()) ->method('request') @@ -907,8 +931,8 @@ final class ApiTest extends TestCase ->willReturn($apiResponse); $this->modelFactoryMock->expects($this->once()) - ->method('createMessage') - ->with($apiResponse['message']) + ->method('createMessageFromSendResponse') + ->with($apiResponse) ->willReturn($expectedMessageObject); $result = $this->api->sendMessage(chatId: $chatId, attachments: [$locationRequest]); @@ -940,11 +964,14 @@ final class ApiTest extends TestCase $apiResponse = [ 'message' => [ 'timestamp' => time(), - 'body' => ['mid' => 'mid.share.1', 'seq' => 13], + 'message' => ['mid' => 'mid.share.1', 'seq' => 13], 'recipient' => ['chat_type' => 'dialog', 'user_id' => $chatId], ] ]; - $expectedMessageObject = Message::fromArray($apiResponse['message']); + $finalMessageData = $apiResponse['message']; + $finalMessageData['body'] = $finalMessageData['message']; + unset($finalMessageData['message']); + $expectedMessageObject = Message::fromArray($finalMessageData); $this->clientMock->expects($this->once()) ->method('request') @@ -952,8 +979,8 @@ final class ApiTest extends TestCase ->willReturn($apiResponse); $this->modelFactoryMock->expects($this->once()) - ->method('createMessage') - ->with($apiResponse['message']) + ->method('createMessageFromSendResponse') + ->with($apiResponse) ->willReturn($expectedMessageObject); $result = $this->api->sendMessage(chatId: $chatId, attachments: [$shareRequest]); diff --git a/tests/ModelFactoryTest.php b/tests/ModelFactoryTest.php index cf63bdf..1f4859c 100644 --- a/tests/ModelFactoryTest.php +++ b/tests/ModelFactoryTest.php @@ -220,6 +220,36 @@ final class ModelFactoryTest extends TestCase $this->assertSame(UpdateType::MessageCreated, $subscriptions[0]->updateTypes[0]); } + #[Test] + public function createMessageFromSendResponseCorrectlyTransformsData(): void + { + $apiResponse = [ + 'message' => [ + 'recipient' => ['chat_id' => 20414985, 'chat_type' => 'dialog', 'user_id' => 4328369], + 'timestamp' => 1760089962345, + 'sender' => [ + 'user_id' => 24480184, + 'first_name' => 'Autobot', + 'is_bot' => true, + 'last_activity_time' => 1760089962354, + ], + 'message' => ['mid' => 'mid.xyz', 'seq' => 1153, 'text' => '123123'], + ], + 'chat_id' => 20414985, + 'recipient_id' => 4328369, + 'message_id' => 'mid.xyz', + ]; + + $message = $this->factory->createMessageFromSendResponse($apiResponse); + + $this->assertInstanceOf(Message::class, $message); + $this->assertInstanceOf(MessageBody::class, $message->body); + $this->assertSame('mid.xyz', $message->body->mid); + $this->assertSame(20414985, $message->chatId); + $this->assertSame(4328369, $message->recipientId); + $this->assertSame('mid.xyz', $message->messageId); + } + #[Test] public function createMessage(): void {