From 4c6e854d6512760ae45d52e3cbc9b4463234346d Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 08:14:35 +0300 Subject: [PATCH 01/32] Add `supportsGuestQueries` field to `User` type. --- CHANGELOG.md | 4 ++++ src/Type/User.php | 2 ++ tests/Type/UserTest.php | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d5ca01d..a2dec32f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Telegram Bot API for PHP Change Log +## 0.21 May 9, 2026 + +- New #199: Add `supportsGuestQueries` field to `User` type. + ## 0.20 April 26, 2026 - Chg #197: `$data` parameter type in `TransportInterface::postWithFiles()` changed from `array` diff --git a/src/Type/User.php b/src/Type/User.php index a46ae50a..a02384fe 100644 --- a/src/Type/User.php +++ b/src/Type/User.php @@ -22,6 +22,7 @@ public function __construct( public ?true $addedToAttachmentMenu = null, public ?bool $canJoinGroups = null, public ?bool $canReadAllGroupMessages = null, + public ?bool $supportsGuestQueries = null, public ?bool $supportsInlineQueries = null, public ?bool $canConnectToBusiness = null, public ?bool $hasMainWebApp = null, @@ -44,6 +45,7 @@ public function toRequestArray(): array 'added_to_attachment_menu' => $this->addedToAttachmentMenu, 'can_join_groups' => $this->canJoinGroups, 'can_read_all_group_messages' => $this->canReadAllGroupMessages, + 'supports_guest_queries' => $this->supportsGuestQueries, 'supports_inline_queries' => $this->supportsInlineQueries, 'can_connect_to_business' => $this->canConnectToBusiness, 'has_main_web_app' => $this->hasMainWebApp, diff --git a/tests/Type/UserTest.php b/tests/Type/UserTest.php index e6e3c3c4..05a67ae7 100644 --- a/tests/Type/UserTest.php +++ b/tests/Type/UserTest.php @@ -28,6 +28,7 @@ public function testBase(): void assertNull($user->addedToAttachmentMenu); assertNull($user->canJoinGroups); assertNull($user->canReadAllGroupMessages); + assertNull($user->supportsGuestQueries); assertNull($user->supportsInlineQueries); assertNull($user->canConnectToBusiness); assertNull($user->hasMainWebApp); @@ -51,6 +52,7 @@ public function testToRequestArray(): void true, true, true, + true, false, true, true, @@ -69,6 +71,7 @@ public function testToRequestArray(): void 'added_to_attachment_menu' => true, 'can_join_groups' => true, 'can_read_all_group_messages' => true, + 'supports_guest_queries' => true, 'supports_inline_queries' => true, 'can_connect_to_business' => true, 'has_main_web_app' => false, @@ -93,6 +96,7 @@ public function testFromTelegramResult(): void 'added_to_attachment_menu' => true, 'can_join_groups' => true, 'can_read_all_group_messages' => true, + 'supports_guest_queries' => true, 'supports_inline_queries' => true, 'can_connect_to_business' => true, 'has_main_web_app' => false, @@ -112,6 +116,7 @@ public function testFromTelegramResult(): void assertSame(true, $user->addedToAttachmentMenu); assertSame(true, $user->canJoinGroups); assertSame(true, $user->canReadAllGroupMessages); + assertSame(true, $user->supportsGuestQueries); assertSame(true, $user->supportsInlineQueries); assertSame(true, $user->canConnectToBusiness); assertSame(false, $user->hasMainWebApp); From 42b56eb13df4edd83e1bbad8d1c0d3d4a029ef10 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 08:19:35 +0300 Subject: [PATCH 02/32] Add `guestQueryId`, `guestBotCallerUser` and `guestBotCallerChat` fields to `Message` type --- CHANGELOG.md | 1 + src/Type/Message.php | 3 +++ tests/Type/MessageTest.php | 16 ++++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2dec32f..9a635349 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 0.21 May 9, 2026 - New #199: Add `supportsGuestQueries` field to `User` type. +- New #199: Add `guestQueryId`, `guestBotCallerUser` and `guestBotCallerChat` fields to `Message` type. ## 0.20 April 26, 2026 diff --git a/src/Type/Message.php b/src/Type/Message.php index 04a531bb..0d35a7a0 100644 --- a/src/Type/Message.php +++ b/src/Type/Message.php @@ -39,6 +39,7 @@ public function __construct( public ?User $senderBusinessBot = null, public ?string $senderTag = null, public ?string $businessConnectionId = null, + public ?string $guestQueryId = null, public ?MessageOrigin $forwardOrigin = null, public ?true $isTopicMessage = null, public ?true $isAutomaticForward = null, @@ -47,6 +48,8 @@ public function __construct( public ?TextQuote $quote = null, public ?Story $replyToStory = null, public ?User $viaBot = null, + public ?User $guestBotCallerUser = null, + public ?Chat $guestBotCallerChat = null, public ?DateTimeImmutable $editDate = null, public ?true $hasProtectedContent = null, public ?true $isFromOffline = null, diff --git a/tests/Type/MessageTest.php b/tests/Type/MessageTest.php index 7d7e3699..664900ca 100644 --- a/tests/Type/MessageTest.php +++ b/tests/Type/MessageTest.php @@ -51,6 +51,7 @@ public function testBase(): void assertNull($message->senderBusinessBot); assertNull($message->senderTag); assertNull($message->businessConnectionId); + assertNull($message->guestQueryId); assertNull($message->forwardOrigin); assertNull($message->isTopicMessage); assertNull($message->isAutomaticForward); @@ -59,6 +60,8 @@ public function testBase(): void assertNull($message->quote); assertNull($message->replyToStory); assertNull($message->viaBot); + assertNull($message->guestBotCallerUser); + assertNull($message->guestBotCallerChat); assertNull($message->editDate); assertNull($message->hasProtectedContent); assertNull($message->isFromOffline); @@ -182,6 +185,7 @@ public function testFromTelegramResult(): void ], 'sender_tag' => 'admin-tag', 'business_connection_id' => 'btest', + 'guest_query_id' => 'guest_query_123', 'forward_origin' => [ 'type' => 'hidden_user', 'date' => 1234156479, @@ -222,6 +226,15 @@ public function testFromTelegramResult(): void 'is_bot' => false, 'first_name' => 'John6Bot', ], + 'guest_bot_caller_user' => [ + 'id' => 128, + 'is_bot' => false, + 'first_name' => 'GuestCaller', + ], + 'guest_bot_caller_chat' => [ + 'id' => 129, + 'type' => 'private', + ], 'edit_date' => 65416841123, 'has_protected_content' => true, 'is_from_offline' => true, @@ -684,6 +697,7 @@ public function testFromTelegramResult(): void assertSame(15, $message->senderBusinessBot?->id); assertSame('admin-tag', $message->senderTag); assertSame('btest', $message->businessConnectionId); + assertSame('guest_query_123', $message->guestQueryId); assertInstanceOf(MessageOriginHiddenUser::class, $message->forwardOrigin); assertSame('bat', $message->forwardOrigin?->senderUserName); @@ -698,6 +712,8 @@ public function testFromTelegramResult(): void assertSame('test93', $message->quote?->text); assertSame(8863, $message->replyToStory?->id); assertSame(127, $message->viaBot?->id); + assertSame(128, $message->guestBotCallerUser?->id); + assertSame(129, $message->guestBotCallerChat?->id); assertSame(65416841123, $message->editDate?->getTimestamp()); assertTrue($message->hasProtectedContent); assertTrue($message->isFromOffline); From a2dfb622625aa2a1fe68668da8cab74c6373a7d4 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 08:22:59 +0300 Subject: [PATCH 03/32] Add `guestMessage` field to `Update` type --- CHANGELOG.md | 1 + src/Type/Update/Update.php | 1 + tests/Type/Update/UpdateTest.php | 13 +++++++++++++ 3 files changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a635349..32551e4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - New #199: Add `supportsGuestQueries` field to `User` type. - New #199: Add `guestQueryId`, `guestBotCallerUser` and `guestBotCallerChat` fields to `Message` type. +- New #199: Add `guestMessage` field to `Update` type. ## 0.20 April 26, 2026 diff --git a/src/Type/Update/Update.php b/src/Type/Update/Update.php index 8feb5952..f510e6df 100644 --- a/src/Type/Update/Update.php +++ b/src/Type/Update/Update.php @@ -49,6 +49,7 @@ public function __construct( public readonly ?Message $businessMessage = null, public readonly ?Message $editedBusinessMessage = null, public readonly ?BusinessMessagesDeleted $deletedBusinessMessages = null, + public readonly ?Message $guestMessage = null, public readonly ?MessageReactionUpdated $messageReaction = null, public readonly ?MessageReactionCountUpdated $messageReactionCount = null, public readonly ?InlineQuery $inlineQuery = null, diff --git a/tests/Type/Update/UpdateTest.php b/tests/Type/Update/UpdateTest.php index 56b2754f..578a8c10 100644 --- a/tests/Type/Update/UpdateTest.php +++ b/tests/Type/Update/UpdateTest.php @@ -31,6 +31,7 @@ public function testBase(): void assertNull($update->businessMessage); assertNull($update->editedBusinessMessage); assertNull($update->deletedBusinessMessages); + assertNull($update->guestMessage); assertNull($update->messageReaction); assertNull($update->messageReactionCount); assertNull($update->inlineQuery); @@ -131,6 +132,16 @@ public function testFromTelegramResult(): void ], 'message_ids' => [7, 8], ], + 'guest_message' => [ + 'message_id' => 9, + 'date' => 1625150000, + 'chat' => [ + 'id' => 23, + 'type' => 'private', + ], + 'guest_query_id' => 'guest_123', + 'text' => 'Guest message', + ], 'message_reaction' => [ 'chat' => [ 'id' => 23, @@ -362,6 +373,8 @@ public function testFromTelegramResult(): void assertSame(5, $update->businessMessage?->messageId); assertSame(6, $update->editedBusinessMessage?->messageId); assertSame('bcid2', $update->deletedBusinessMessages?->businessConnectionId); + assertSame(9, $update->guestMessage?->messageId); + assertSame('guest_123', $update->guestMessage?->guestQueryId); assertSame(79, $update->messageReaction?->messageId); assertSame(80, $update->messageReactionCount?->messageId); assertSame('iqid1', $update->inlineQuery?->id); From af862fae8ab3a9a83065acaf16c3e8b0df5d9338 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 08:26:43 +0300 Subject: [PATCH 04/32] Add `SentGuestMessage` type --- CHANGELOG.md | 1 + src/Type/SentGuestMessage.php | 17 +++++++++++++++++ tests/Type/SentGuestMessageTest.php | 28 ++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 src/Type/SentGuestMessage.php create mode 100644 tests/Type/SentGuestMessageTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 32551e4b..f1afcf64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - New #199: Add `supportsGuestQueries` field to `User` type. - New #199: Add `guestQueryId`, `guestBotCallerUser` and `guestBotCallerChat` fields to `Message` type. - New #199: Add `guestMessage` field to `Update` type. +- New #199: Add `SentGuestMessage` type. ## 0.20 April 26, 2026 diff --git a/src/Type/SentGuestMessage.php b/src/Type/SentGuestMessage.php new file mode 100644 index 00000000..6abd95c1 --- /dev/null +++ b/src/Type/SentGuestMessage.php @@ -0,0 +1,17 @@ +inlineMessageId); + } + + public function testFromTelegramResult(): void + { + $type = (new ObjectFactory())->create(['inline_message_id' => 'inline_msg_456'], null, SentGuestMessage::class); + + assertSame('inline_msg_456', $type->inlineMessageId); + } +} From b71acc377a7c00aadb0560b2fe3a32e475b9d933 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 08:32:50 +0300 Subject: [PATCH 05/32] Add `AnswerGuestQuery` method --- CHANGELOG.md | 1 + src/Method/Inline/AnswerGuestQuery.php | 47 ++++++++++++++++++++ src/TelegramBotApi.php | 12 +++++ tests/Method/Inline/AnswerGuestQueryTest.php | 43 ++++++++++++++++++ tests/TelegramBotApi/TelegramBotApiTest.php | 13 ++++++ 5 files changed, 116 insertions(+) create mode 100644 src/Method/Inline/AnswerGuestQuery.php create mode 100644 tests/Method/Inline/AnswerGuestQueryTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index f1afcf64..b9e0ee90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - New #199: Add `guestQueryId`, `guestBotCallerUser` and `guestBotCallerChat` fields to `Message` type. - New #199: Add `guestMessage` field to `Update` type. - New #199: Add `SentGuestMessage` type. +- New #199: Add `AnswerGuestQuery` method. ## 0.20 April 26, 2026 diff --git a/src/Method/Inline/AnswerGuestQuery.php b/src/Method/Inline/AnswerGuestQuery.php new file mode 100644 index 00000000..f76ee7a6 --- /dev/null +++ b/src/Method/Inline/AnswerGuestQuery.php @@ -0,0 +1,47 @@ + + */ +final readonly class AnswerGuestQuery implements MethodInterface +{ + public function __construct( + private string $guestQueryId, + private InlineQueryResult $result, + ) {} + + public function getHttpMethod(): HttpMethod + { + return HttpMethod::POST; + } + + public function getApiMethod(): string + { + return 'answerGuestQuery'; + } + + public function getData(): array + { + return [ + 'guest_query_id' => $this->guestQueryId, + 'result' => $this->result->toRequestArray(), + ]; + } + + public function getResultType(): ObjectValue + { + return new ObjectValue(SentGuestMessage::class); + } +} diff --git a/src/TelegramBotApi.php b/src/TelegramBotApi.php index 45c9da1d..fd744d64 100644 --- a/src/TelegramBotApi.php +++ b/src/TelegramBotApi.php @@ -66,6 +66,7 @@ use Phptg\BotApi\Method\GetUserProfilePhotos; use Phptg\BotApi\Method\GiftPremiumSubscription; use Phptg\BotApi\Method\HideGeneralForumTopic; +use Phptg\BotApi\Method\Inline\AnswerGuestQuery; use Phptg\BotApi\Method\Inline\AnswerInlineQuery; use Phptg\BotApi\Method\Inline\AnswerWebAppQuery; use Phptg\BotApi\Method\Inline\SavePreparedInlineMessage; @@ -238,6 +239,7 @@ use Phptg\BotApi\Type\Sticker\Sticker; use Phptg\BotApi\Type\Sticker\StickerSet; use Phptg\BotApi\Type\Story; +use Phptg\BotApi\Type\SentGuestMessage; use Phptg\BotApi\Type\SuggestedPostParameters; use Phptg\BotApi\Type\StoryArea; use Phptg\BotApi\Type\Update\Update; @@ -430,6 +432,16 @@ public function answerShippingQuery( ); } + /** + * @see https://core.telegram.org/bots/api#answerguestquery + */ + public function answerGuestQuery(string $guestQueryId, InlineQueryResult $result): FailResult|SentGuestMessage + { + return $this->call( + new AnswerGuestQuery($guestQueryId, $result), + ); + } + /** * @see https://core.telegram.org/bots/api#answerwebappquery */ diff --git a/tests/Method/Inline/AnswerGuestQueryTest.php b/tests/Method/Inline/AnswerGuestQueryTest.php new file mode 100644 index 00000000..9990f96a --- /dev/null +++ b/tests/Method/Inline/AnswerGuestQueryTest.php @@ -0,0 +1,43 @@ +getHttpMethod()); + assertSame('answerGuestQuery', $method->getApiMethod()); + assertSame( + [ + 'guest_query_id' => 'guest_id_123', + 'result' => $result->toRequestArray(), + ], + $method->getData(), + ); + } + + public function testPrepareResult(): void + { + $method = new AnswerGuestQuery('guest_id_456', new InlineQueryResultContact('1', '+79001234567', 'Vjik')); + + $preparedResult = TestHelper::createSuccessStubApi([ + 'inline_message_id' => 'guest_msg_789', + ])->call($method); + + assertSame('guest_msg_789', $preparedResult->inlineMessageId); + } +} diff --git a/tests/TelegramBotApi/TelegramBotApiTest.php b/tests/TelegramBotApi/TelegramBotApiTest.php index 662d513b..7faf66de 100644 --- a/tests/TelegramBotApi/TelegramBotApiTest.php +++ b/tests/TelegramBotApi/TelegramBotApiTest.php @@ -31,6 +31,7 @@ use Phptg\BotApi\Type\Inline\InlineQueryResultGame; use Phptg\BotApi\Type\Inline\PreparedInlineMessage; use Phptg\BotApi\Type\Inline\SentWebAppMessage; +use Phptg\BotApi\Type\SentGuestMessage; use Phptg\BotApi\Type\InputChecklist; use Phptg\BotApi\Type\InputFile; use Phptg\BotApi\Type\InputMediaPhoto; @@ -496,6 +497,18 @@ public function testAnswerCallbackQuery(): void assertTrue($result); } + public function testAnswerGuestQuery(): void + { + $api = TestHelper::createSuccessStubApi([ + 'inline_message_id' => 'guest_msg_123', + ]); + + $result = $api->answerGuestQuery('guest_id', new InlineQueryResultContact('1', '+79001234567', 'Vjik')); + + assertInstanceOf(SentGuestMessage::class, $result); + assertSame('guest_msg_123', $result->inlineMessageId); + } + public function testAnswerInlineQuery(): void { $api = TestHelper::createSuccessStubApi(true); From 0dee8c06db4c835084412e148c053c5f989bb0e8 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 08:37:16 +0300 Subject: [PATCH 06/32] Add `canReactToMessages` field to `ChatMemberRestricted` and `ChatPermissions` types --- CHANGELOG.md | 1 + src/Type/ChatMemberRestricted.php | 1 + src/Type/ChatPermissions.php | 2 ++ tests/ParseResult/ValueProcessor/ChatMemberValueTest.php | 1 + tests/Type/ChatMemberRestrictedTest.php | 6 ++++++ tests/Type/ChatPermissionsTest.php | 5 +++++ 6 files changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9e0ee90..5f96f287 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - New #199: Add `guestMessage` field to `Update` type. - New #199: Add `SentGuestMessage` type. - New #199: Add `AnswerGuestQuery` method. +- New #199: Add `canReactToMessages` field to `ChatMemberRestricted` and `ChatPermissions` types. ## 0.20 April 26, 2026 diff --git a/src/Type/ChatMemberRestricted.php b/src/Type/ChatMemberRestricted.php index 15390103..f00233b1 100644 --- a/src/Type/ChatMemberRestricted.php +++ b/src/Type/ChatMemberRestricted.php @@ -27,6 +27,7 @@ public function __construct( public bool $canSendPolls, public bool $canSendOtherMessages, public bool $canAddWebPagePreviews, + public bool $canReactToMessages, public bool $canEditTag, public bool $canChangeInfo, public bool $canInviteUsers, diff --git a/src/Type/ChatPermissions.php b/src/Type/ChatPermissions.php index 6a67d227..4603439f 100644 --- a/src/Type/ChatPermissions.php +++ b/src/Type/ChatPermissions.php @@ -22,6 +22,7 @@ public function __construct( public ?bool $canSendPolls = null, public ?bool $canSendOtherMessages = null, public ?bool $canAddWebPagePreviews = null, + public ?bool $canReactToMessages = null, public ?bool $canEditTag = null, public ?bool $canChangeInfo = null, public ?bool $canInviteUsers = null, @@ -43,6 +44,7 @@ public function toRequestArray(): array 'can_send_polls' => $this->canSendPolls, 'can_send_other_messages' => $this->canSendOtherMessages, 'can_add_web_page_previews' => $this->canAddWebPagePreviews, + 'can_react_to_messages' => $this->canReactToMessages, 'can_edit_tag' => $this->canEditTag, 'can_change_info' => $this->canChangeInfo, 'can_invite_users' => $this->canInviteUsers, diff --git a/tests/ParseResult/ValueProcessor/ChatMemberValueTest.php b/tests/ParseResult/ValueProcessor/ChatMemberValueTest.php index aa4da919..c6007fbb 100644 --- a/tests/ParseResult/ValueProcessor/ChatMemberValueTest.php +++ b/tests/ParseResult/ValueProcessor/ChatMemberValueTest.php @@ -89,6 +89,7 @@ public static function dataBase(): array 'can_send_polls' => false, 'can_send_other_messages' => false, 'can_add_web_page_previews' => false, + 'can_react_to_messages' => false, 'can_edit_tag' => false, 'can_change_info' => false, 'can_invite_users' => false, diff --git a/tests/Type/ChatMemberRestrictedTest.php b/tests/Type/ChatMemberRestrictedTest.php index bed96e7a..2119ac6a 100644 --- a/tests/Type/ChatMemberRestrictedTest.php +++ b/tests/Type/ChatMemberRestrictedTest.php @@ -39,6 +39,7 @@ public function testBase(): void true, true, true, + true, false, ); @@ -56,6 +57,7 @@ public function testBase(): void assertTrue($member->canSendPolls); assertTrue($member->canSendOtherMessages); assertTrue($member->canAddWebPagePreviews); + assertTrue($member->canReactToMessages); assertTrue($member->canEditTag); assertTrue($member->canChangeInfo); assertTrue($member->canInviteUsers); @@ -84,6 +86,7 @@ public function testFromTelegramResult(): void 'can_send_polls' => true, 'can_send_other_messages' => true, 'can_add_web_page_previews' => true, + 'can_react_to_messages' => true, 'can_edit_tag' => true, 'can_change_info' => true, 'can_invite_users' => true, @@ -105,6 +108,7 @@ public function testFromTelegramResult(): void assertTrue($member->canSendPolls); assertTrue($member->canSendOtherMessages); assertTrue($member->canAddWebPagePreviews); + assertTrue($member->canReactToMessages); assertTrue($member->canEditTag); assertTrue($member->canChangeInfo); assertTrue($member->canInviteUsers); @@ -133,6 +137,7 @@ public function testFromTelegramResultWithZeroUntilDate(): void 'can_send_polls' => true, 'can_send_other_messages' => true, 'can_add_web_page_previews' => true, + 'can_react_to_messages' => true, 'can_edit_tag' => true, 'can_change_info' => true, 'can_invite_users' => true, @@ -153,6 +158,7 @@ public function testFromTelegramResultWithZeroUntilDate(): void assertTrue($member->canSendPolls); assertTrue($member->canSendOtherMessages); assertTrue($member->canAddWebPagePreviews); + assertTrue($member->canReactToMessages); assertTrue($member->canEditTag); assertTrue($member->canChangeInfo); assertTrue($member->canInviteUsers); diff --git a/tests/Type/ChatPermissionsTest.php b/tests/Type/ChatPermissionsTest.php index 844467d4..1fe7fb08 100644 --- a/tests/Type/ChatPermissionsTest.php +++ b/tests/Type/ChatPermissionsTest.php @@ -29,6 +29,7 @@ public function testBase(): void assertNull($chatPermissions->canSendPolls); assertNull($chatPermissions->canSendOtherMessages); assertNull($chatPermissions->canAddWebPagePreviews); + assertNull($chatPermissions->canReactToMessages); assertNull($chatPermissions->canEditTag); assertNull($chatPermissions->canChangeInfo); assertNull($chatPermissions->canInviteUsers); @@ -51,6 +52,7 @@ public function testFull(): void true, true, true, + true, false, false, true, @@ -69,6 +71,7 @@ public function testFull(): void 'can_send_polls' => false, 'can_send_other_messages' => true, 'can_add_web_page_previews' => true, + 'can_react_to_messages' => true, 'can_edit_tag' => true, 'can_change_info' => false, 'can_invite_users' => false, @@ -92,6 +95,7 @@ public function testFromTelegramResult(): void 'can_send_polls' => true, 'can_send_other_messages' => true, 'can_add_web_page_previews' => true, + 'can_react_to_messages' => true, 'can_edit_tag' => true, 'can_change_info' => true, 'can_invite_users' => true, @@ -109,6 +113,7 @@ public function testFromTelegramResult(): void assertTrue($chatPermissions->canSendPolls); assertTrue($chatPermissions->canSendOtherMessages); assertTrue($chatPermissions->canAddWebPagePreviews); + assertTrue($chatPermissions->canReactToMessages); assertTrue($chatPermissions->canEditTag); assertTrue($chatPermissions->canChangeInfo); assertTrue($chatPermissions->canInviteUsers); From 46e1412af9f2b89630a886e98b4c29db6f2b197f Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 08:41:24 +0300 Subject: [PATCH 07/32] Add `returnBots` parameter to `GetChatAdministrators` method --- CHANGELOG.md | 1 + src/Method/GetChatAdministrators.php | 9 ++++++++- src/TelegramBotApi.php | 4 ++-- tests/Method/GetChatAdministratorsTest.php | 15 +++++++++++++++ 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f96f287..cad8f67b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - New #199: Add `SentGuestMessage` type. - New #199: Add `AnswerGuestQuery` method. - New #199: Add `canReactToMessages` field to `ChatMemberRestricted` and `ChatPermissions` types. +- New #199: Add `returnBots` parameter to `GetChatAdministrators` method. ## 0.20 April 26, 2026 diff --git a/src/Method/GetChatAdministrators.php b/src/Method/GetChatAdministrators.php index 19f50917..c3c4cfe4 100644 --- a/src/Method/GetChatAdministrators.php +++ b/src/Method/GetChatAdministrators.php @@ -19,6 +19,7 @@ { public function __construct( private int|string $chatId, + private ?bool $returnBots = null, ) {} public function getHttpMethod(): HttpMethod @@ -33,7 +34,13 @@ public function getApiMethod(): string public function getData(): array { - return ['chat_id' => $this->chatId]; + return array_filter( + [ + 'chat_id' => $this->chatId, + 'return_bots' => $this->returnBots, + ], + static fn(mixed $value): bool => $value !== null, + ); } public function getResultType(): ArrayMap diff --git a/src/TelegramBotApi.php b/src/TelegramBotApi.php index fd744d64..06aa0a05 100644 --- a/src/TelegramBotApi.php +++ b/src/TelegramBotApi.php @@ -1285,9 +1285,9 @@ public function getChatGifts( * * @return FailResult|ChatMember[] */ - public function getChatAdministrators(int|string $chatId): FailResult|array + public function getChatAdministrators(int|string $chatId, ?bool $returnBots = null): FailResult|array { - return $this->call(new GetChatAdministrators($chatId)); + return $this->call(new GetChatAdministrators($chatId, $returnBots)); } /** diff --git a/tests/Method/GetChatAdministratorsTest.php b/tests/Method/GetChatAdministratorsTest.php index c90e74d4..46aa3785 100644 --- a/tests/Method/GetChatAdministratorsTest.php +++ b/tests/Method/GetChatAdministratorsTest.php @@ -30,6 +30,21 @@ public function testBase(): void ); } + public function testWithReturnBots(): void + { + $method = new GetChatAdministrators(1, true); + + assertSame(HttpMethod::GET, $method->getHttpMethod()); + assertSame('getChatAdministrators', $method->getApiMethod()); + assertSame( + [ + 'chat_id' => 1, + 'return_bots' => true, + ], + $method->getData(), + ); + } + public function testPrepareResult(): void { $method = new GetChatAdministrators(1); From 8774b6e6d701a3c32476a1400f2788095fb48a33 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 08:47:32 +0300 Subject: [PATCH 08/32] Add `DeleteAllMessageReactions` method --- CHANGELOG.md | 1 + src/Method/DeleteAllMessageReactions.php | 50 +++++++++++++++++ src/TelegramBotApi.php | 14 +++++ .../Method/DeleteAllMessageReactionsTest.php | 55 +++++++++++++++++++ tests/TelegramBotApi/TelegramBotApiTest.php | 9 +++ 5 files changed, 129 insertions(+) create mode 100644 src/Method/DeleteAllMessageReactions.php create mode 100644 tests/Method/DeleteAllMessageReactionsTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index cad8f67b..823bf5aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - New #199: Add `AnswerGuestQuery` method. - New #199: Add `canReactToMessages` field to `ChatMemberRestricted` and `ChatPermissions` types. - New #199: Add `returnBots` parameter to `GetChatAdministrators` method. +- New #199: Add `DeleteAllMessageReactions` method. ## 0.20 April 26, 2026 diff --git a/src/Method/DeleteAllMessageReactions.php b/src/Method/DeleteAllMessageReactions.php new file mode 100644 index 00000000..374fbfb3 --- /dev/null +++ b/src/Method/DeleteAllMessageReactions.php @@ -0,0 +1,50 @@ + + */ +final readonly class DeleteAllMessageReactions implements MethodInterface +{ + public function __construct( + private int|string $chatId, + private ?int $userId = null, + private ?int $actorChatId = null, + ) {} + + public function getHttpMethod(): HttpMethod + { + return HttpMethod::POST; + } + + public function getApiMethod(): string + { + return 'deleteAllMessageReactions'; + } + + public function getData(): array + { + return array_filter( + [ + 'chat_id' => $this->chatId, + 'user_id' => $this->userId, + 'actor_chat_id' => $this->actorChatId, + ], + static fn(mixed $value): bool => $value !== null, + ); + } + + public function getResultType(): TrueValue + { + return new TrueValue(); + } +} diff --git a/src/TelegramBotApi.php b/src/TelegramBotApi.php index 06aa0a05..89a00f6b 100644 --- a/src/TelegramBotApi.php +++ b/src/TelegramBotApi.php @@ -25,6 +25,7 @@ use Phptg\BotApi\Method\CreateForumTopic; use Phptg\BotApi\Method\DeclineChatJoinRequest; use Phptg\BotApi\Method\DeclineSuggestedPost; +use Phptg\BotApi\Method\DeleteAllMessageReactions; use Phptg\BotApi\Method\DeleteChatPhoto; use Phptg\BotApi\Method\DeleteChatStickerSet; use Phptg\BotApi\Method\DeleteForumTopic; @@ -749,6 +750,19 @@ public function declineSuggestedPost(int $chatId, int $messageId, ?string $comme ); } + /** + * @see https://core.telegram.org/bots/api#deleteallmessagereactions + */ + public function deleteAllMessageReactions( + int|string $chatId, + ?int $userId = null, + ?int $actorChatId = null, + ): FailResult|true { + return $this->call( + new DeleteAllMessageReactions($chatId, $userId, $actorChatId), + ); + } + /** * @see https://core.telegram.org/bots/api#deletebusinessmessages * diff --git a/tests/Method/DeleteAllMessageReactionsTest.php b/tests/Method/DeleteAllMessageReactionsTest.php new file mode 100644 index 00000000..9191f1d6 --- /dev/null +++ b/tests/Method/DeleteAllMessageReactionsTest.php @@ -0,0 +1,55 @@ +getHttpMethod()); + assertSame('deleteAllMessageReactions', $method->getApiMethod()); + assertSame( + [ + 'chat_id' => 1, + ], + $method->getData(), + ); + } + + public function testFull(): void + { + $method = new DeleteAllMessageReactions(1, 123, 456); + + assertSame(HttpMethod::POST, $method->getHttpMethod()); + assertSame('deleteAllMessageReactions', $method->getApiMethod()); + assertSame( + [ + 'chat_id' => 1, + 'user_id' => 123, + 'actor_chat_id' => 456, + ], + $method->getData(), + ); + } + + public function testPrepareResult(): void + { + $method = new DeleteAllMessageReactions(1); + + $result = TestHelper::createSuccessStubApi(true)->call($method); + + assertTrue($result); + } +} diff --git a/tests/TelegramBotApi/TelegramBotApiTest.php b/tests/TelegramBotApi/TelegramBotApiTest.php index 7faf66de..6222d138 100644 --- a/tests/TelegramBotApi/TelegramBotApiTest.php +++ b/tests/TelegramBotApi/TelegramBotApiTest.php @@ -744,6 +744,15 @@ public function testDeclineSuggestedPost(): void assertTrue($result); } + public function testDeleteAllMessageReactions(): void + { + $api = TestHelper::createSuccessStubApi(true); + + $result = $api->deleteAllMessageReactions(1); + + assertTrue($result); + } + public function testDeleteBusinessMessages(): void { $api = TestHelper::createSuccessStubApi(true); From 1880bafbb443dd64cdf3abd1ecf170de3615e412 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 08:51:26 +0300 Subject: [PATCH 09/32] Add `DeleteMessageReaction` method --- CHANGELOG.md | 1 + src/Method/DeleteMessageReaction.php | 52 +++++++++++++++++++ src/TelegramBotApi.php | 15 ++++++ tests/Method/DeleteMessageReactionTest.php | 57 +++++++++++++++++++++ tests/TelegramBotApi/TelegramBotApiTest.php | 9 ++++ 5 files changed, 134 insertions(+) create mode 100644 src/Method/DeleteMessageReaction.php create mode 100644 tests/Method/DeleteMessageReactionTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 823bf5aa..7aac02a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - New #199: Add `canReactToMessages` field to `ChatMemberRestricted` and `ChatPermissions` types. - New #199: Add `returnBots` parameter to `GetChatAdministrators` method. - New #199: Add `DeleteAllMessageReactions` method. +- New #199: Add `DeleteMessageReaction` method. ## 0.20 April 26, 2026 diff --git a/src/Method/DeleteMessageReaction.php b/src/Method/DeleteMessageReaction.php new file mode 100644 index 00000000..8320afa9 --- /dev/null +++ b/src/Method/DeleteMessageReaction.php @@ -0,0 +1,52 @@ + + */ +final readonly class DeleteMessageReaction implements MethodInterface +{ + public function __construct( + private int|string $chatId, + private int $messageId, + private ?int $userId = null, + private ?int $actorChatId = null, + ) {} + + public function getHttpMethod(): HttpMethod + { + return HttpMethod::POST; + } + + public function getApiMethod(): string + { + return 'deleteMessageReaction'; + } + + public function getData(): array + { + return array_filter( + [ + 'chat_id' => $this->chatId, + 'message_id' => $this->messageId, + 'user_id' => $this->userId, + 'actor_chat_id' => $this->actorChatId, + ], + static fn(mixed $value): bool => $value !== null, + ); + } + + public function getResultType(): TrueValue + { + return new TrueValue(); + } +} diff --git a/src/TelegramBotApi.php b/src/TelegramBotApi.php index 89a00f6b..efe8361f 100644 --- a/src/TelegramBotApi.php +++ b/src/TelegramBotApi.php @@ -29,6 +29,7 @@ use Phptg\BotApi\Method\DeleteChatPhoto; use Phptg\BotApi\Method\DeleteChatStickerSet; use Phptg\BotApi\Method\DeleteForumTopic; +use Phptg\BotApi\Method\DeleteMessageReaction; use Phptg\BotApi\Method\DeleteMyCommands; use Phptg\BotApi\Method\DeleteStory; use Phptg\BotApi\Method\EditChatInviteLink; @@ -805,6 +806,20 @@ public function deleteForumTopic(int|string $chatId, int $messageThreadId): Fail return $this->call(new DeleteForumTopic($chatId, $messageThreadId)); } + /** + * @see https://core.telegram.org/bots/api#deletemessagereaction + */ + public function deleteMessageReaction( + int|string $chatId, + int $messageId, + ?int $userId = null, + ?int $actorChatId = null, + ): FailResult|true { + return $this->call( + new DeleteMessageReaction($chatId, $messageId, $userId, $actorChatId), + ); + } + /** * @see https://core.telegram.org/bots/api#deletemessage */ diff --git a/tests/Method/DeleteMessageReactionTest.php b/tests/Method/DeleteMessageReactionTest.php new file mode 100644 index 00000000..eec70bc2 --- /dev/null +++ b/tests/Method/DeleteMessageReactionTest.php @@ -0,0 +1,57 @@ +getHttpMethod()); + assertSame('deleteMessageReaction', $method->getApiMethod()); + assertSame( + [ + 'chat_id' => 1, + 'message_id' => 100, + ], + $method->getData(), + ); + } + + public function testFull(): void + { + $method = new DeleteMessageReaction(1, 100, 123, 456); + + assertSame(HttpMethod::POST, $method->getHttpMethod()); + assertSame('deleteMessageReaction', $method->getApiMethod()); + assertSame( + [ + 'chat_id' => 1, + 'message_id' => 100, + 'user_id' => 123, + 'actor_chat_id' => 456, + ], + $method->getData(), + ); + } + + public function testPrepareResult(): void + { + $method = new DeleteMessageReaction(1, 100); + + $result = TestHelper::createSuccessStubApi(true)->call($method); + + assertTrue($result); + } +} diff --git a/tests/TelegramBotApi/TelegramBotApiTest.php b/tests/TelegramBotApi/TelegramBotApiTest.php index 6222d138..612d0349 100644 --- a/tests/TelegramBotApi/TelegramBotApiTest.php +++ b/tests/TelegramBotApi/TelegramBotApiTest.php @@ -789,6 +789,15 @@ public function testDeleteForumTopic(): void assertTrue($result); } + public function testDeleteMessageReaction(): void + { + $api = TestHelper::createSuccessStubApi(true); + + $result = $api->deleteMessageReaction(1, 100); + + assertTrue($result); + } + public function testDeleteMessage(): void { $api = TestHelper::createSuccessStubApi(true); From 053de251ea7e837b52a904fee81abb4bf3ff0154 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 08:59:47 +0300 Subject: [PATCH 10/32] Add `InputMediaSticker`, `InputMediaVenue` and `InputMediaLocation` types --- CHANGELOG.md | 1 + src/Type/InputMediaLocation.php | 39 ++++++++++++++ src/Type/InputMediaSticker.php | 45 ++++++++++++++++ src/Type/InputMediaVenue.php | 49 +++++++++++++++++ tests/Type/InputMediaLocationTest.php | 57 ++++++++++++++++++++ tests/Type/InputMediaStickerTest.php | 58 +++++++++++++++++++++ tests/Type/InputMediaVenueTest.php | 75 +++++++++++++++++++++++++++ 7 files changed, 324 insertions(+) create mode 100644 src/Type/InputMediaLocation.php create mode 100644 src/Type/InputMediaSticker.php create mode 100644 src/Type/InputMediaVenue.php create mode 100644 tests/Type/InputMediaLocationTest.php create mode 100644 tests/Type/InputMediaStickerTest.php create mode 100644 tests/Type/InputMediaVenueTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 7aac02a8..b92a4809 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - New #199: Add `returnBots` parameter to `GetChatAdministrators` method. - New #199: Add `DeleteAllMessageReactions` method. - New #199: Add `DeleteMessageReaction` method. +- New #199: Add `InputMediaSticker`, `InputMediaVenue` and `InputMediaLocation` types. ## 0.20 April 26, 2026 diff --git a/src/Type/InputMediaLocation.php b/src/Type/InputMediaLocation.php new file mode 100644 index 00000000..c03363b2 --- /dev/null +++ b/src/Type/InputMediaLocation.php @@ -0,0 +1,39 @@ + $this->getType(), + 'latitude' => $this->latitude, + 'longitude' => $this->longitude, + 'horizontal_accuracy' => $this->horizontalAccuracy, + ], + static fn(mixed $value): bool => $value !== null, + ); + } +} diff --git a/src/Type/InputMediaSticker.php b/src/Type/InputMediaSticker.php new file mode 100644 index 00000000..8920f111 --- /dev/null +++ b/src/Type/InputMediaSticker.php @@ -0,0 +1,45 @@ +media instanceof InputFile + ? 'attach://' . $fileCollector->add($this->media) + : $this->media; + } else { + $media = $this->media; + } + + return array_filter( + [ + 'type' => $this->getType(), + 'media' => $media, + 'emoji' => $this->emoji, + ], + static fn(mixed $value): bool => $value !== null, + ); + } +} diff --git a/src/Type/InputMediaVenue.php b/src/Type/InputMediaVenue.php new file mode 100644 index 00000000..033df4af --- /dev/null +++ b/src/Type/InputMediaVenue.php @@ -0,0 +1,49 @@ + $this->getType(), + 'latitude' => $this->latitude, + 'longitude' => $this->longitude, + 'title' => $this->title, + 'address' => $this->address, + 'foursquare_id' => $this->foursquareId, + 'foursquare_type' => $this->foursquareType, + 'google_place_id' => $this->googlePlaceId, + 'google_place_type' => $this->googlePlaceType, + ], + static fn(mixed $value): bool => $value !== null, + ); + } +} diff --git a/tests/Type/InputMediaLocationTest.php b/tests/Type/InputMediaLocationTest.php new file mode 100644 index 00000000..94ddb91f --- /dev/null +++ b/tests/Type/InputMediaLocationTest.php @@ -0,0 +1,57 @@ +getType()); + assertSame( + [ + 'type' => 'location', + 'latitude' => 55.7558, + 'longitude' => 37.6173, + ], + $inputMedia->toRequestArray(), + ); + + $fileCollector = new FileCollector(); + assertSame( + [ + 'type' => 'location', + 'latitude' => 55.7558, + 'longitude' => 37.6173, + ], + $inputMedia->toRequestArray($fileCollector), + ); + assertEmpty($fileCollector->get()); + } + + public function testFull(): void + { + $inputMedia = new InputMediaLocation(55.7558, 37.6173, 500.5); + + assertSame('location', $inputMedia->getType()); + assertSame( + [ + 'type' => 'location', + 'latitude' => 55.7558, + 'longitude' => 37.6173, + 'horizontal_accuracy' => 500.5, + ], + $inputMedia->toRequestArray(), + ); + } +} diff --git a/tests/Type/InputMediaStickerTest.php b/tests/Type/InputMediaStickerTest.php new file mode 100644 index 00000000..a12354ca --- /dev/null +++ b/tests/Type/InputMediaStickerTest.php @@ -0,0 +1,58 @@ +getType()); + assertSame( + [ + 'type' => 'sticker', + 'media' => 'https://example.com/sticker.webp', + ], + $inputMedia->toRequestArray(), + ); + + $fileCollector = new FileCollector(); + assertSame( + [ + 'type' => 'sticker', + 'media' => 'https://example.com/sticker.webp', + ], + $inputMedia->toRequestArray($fileCollector), + ); + assertEmpty($fileCollector->get()); + } + + public function testFull(): void + { + $media = new InputFile(null); + $inputMedia = new InputMediaSticker($media, '😀'); + $fileCollector = new FileCollector(); + + assertSame('sticker', $inputMedia->getType()); + assertSame( + [ + 'type' => 'sticker', + 'media' => 'attach://file0', + 'emoji' => '😀', + ], + $inputMedia->toRequestArray($fileCollector), + ); + assertSame(['file0' => $media], $fileCollector->get()); + } +} diff --git a/tests/Type/InputMediaVenueTest.php b/tests/Type/InputMediaVenueTest.php new file mode 100644 index 00000000..9b5ed4e6 --- /dev/null +++ b/tests/Type/InputMediaVenueTest.php @@ -0,0 +1,75 @@ +getType()); + assertSame( + [ + 'type' => 'venue', + 'latitude' => 55.7558, + 'longitude' => 37.6173, + 'title' => 'The Kremlin', + 'address' => 'Red Square, Moscow', + ], + $inputMedia->toRequestArray(), + ); + + $fileCollector = new FileCollector(); + assertSame( + [ + 'type' => 'venue', + 'latitude' => 55.7558, + 'longitude' => 37.6173, + 'title' => 'The Kremlin', + 'address' => 'Red Square, Moscow', + ], + $inputMedia->toRequestArray($fileCollector), + ); + assertEmpty($fileCollector->get()); + } + + public function testFull(): void + { + $inputMedia = new InputMediaVenue( + 55.7558, + 37.6173, + 'The Kremlin', + 'Red Square, Moscow', + 'foursquare_id_123', + 'arts_entertainment/landmark', + 'google_place_id_456', + 'point_of_interest', + ); + + assertSame('venue', $inputMedia->getType()); + assertSame( + [ + 'type' => 'venue', + 'latitude' => 55.7558, + 'longitude' => 37.6173, + 'title' => 'The Kremlin', + 'address' => 'Red Square, Moscow', + 'foursquare_id' => 'foursquare_id_123', + 'foursquare_type' => 'arts_entertainment/landmark', + 'google_place_id' => 'google_place_id_456', + 'google_place_type' => 'point_of_interest', + ], + $inputMedia->toRequestArray(), + ); + } +} From bf5eed96ab8fe65db4665f5bc564e0d2b1e42a4e Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 09:16:17 +0300 Subject: [PATCH 11/32] Add `PollMedia` and `LivePhoto` type --- CHANGELOG.md | 1 + src/Type/LivePhoto.php | 30 +++++++++ src/Type/PollMedia.php | 32 ++++++++++ tests/Type/LivePhotoTest.php | 74 ++++++++++++++++++++++ tests/Type/PollMediaTest.php | 116 +++++++++++++++++++++++++++++++++++ 5 files changed, 253 insertions(+) create mode 100644 src/Type/LivePhoto.php create mode 100644 src/Type/PollMedia.php create mode 100644 tests/Type/LivePhotoTest.php create mode 100644 tests/Type/PollMediaTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index b92a4809..d9061015 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - New #199: Add `DeleteAllMessageReactions` method. - New #199: Add `DeleteMessageReaction` method. - New #199: Add `InputMediaSticker`, `InputMediaVenue` and `InputMediaLocation` types. +- New #199: Add `PollMedia` and `LivePhoto` type. ## 0.20 April 26, 2026 diff --git a/src/Type/LivePhoto.php b/src/Type/LivePhoto.php new file mode 100644 index 00000000..2781ed96 --- /dev/null +++ b/src/Type/LivePhoto.php @@ -0,0 +1,30 @@ +fileId); + assertSame('file_unique_id_456', $livePhoto->fileUniqueId); + assertSame(1280, $livePhoto->width); + assertSame(720, $livePhoto->height); + assertSame(5, $livePhoto->duration); + assertNull($livePhoto->photo); + assertNull($livePhoto->mimeType); + assertNull($livePhoto->fileSize); + } + + public function testFromTelegramResult(): void + { + $livePhoto = (new ObjectFactory())->create([ + 'file_id' => 'file_id_abc', + 'file_unique_id' => 'file_unique_id_def', + 'width' => 1920, + 'height' => 1080, + 'duration' => 10, + 'photo' => [ + [ + 'file_id' => 'photo_file_id_1', + 'file_unique_id' => 'photo_unique_id_1', + 'width' => 1920, + 'height' => 1080, + ], + [ + 'file_id' => 'photo_file_id_2', + 'file_unique_id' => 'photo_unique_id_2', + 'width' => 960, + 'height' => 540, + ], + ], + 'mime_type' => 'video/mp4', + 'file_size' => '2097152', + ], null, LivePhoto::class); + + assertSame('file_id_abc', $livePhoto->fileId); + assertSame('file_unique_id_def', $livePhoto->fileUniqueId); + assertSame(1920, $livePhoto->width); + assertSame(1080, $livePhoto->height); + assertSame(10, $livePhoto->duration); + assertCount(2, $livePhoto->photo); + assertSame('photo_file_id_1', $livePhoto->photo[0]->fileId); + assertSame('photo_file_id_2', $livePhoto->photo[1]->fileId); + assertSame('video/mp4', $livePhoto->mimeType); + assertSame('2097152', $livePhoto->fileSize); + } +} diff --git a/tests/Type/PollMediaTest.php b/tests/Type/PollMediaTest.php new file mode 100644 index 00000000..ec456d66 --- /dev/null +++ b/tests/Type/PollMediaTest.php @@ -0,0 +1,116 @@ +animation); + assertNull($pollMedia->audio); + assertNull($pollMedia->document); + assertNull($pollMedia->livePhoto); + assertNull($pollMedia->location); + assertNull($pollMedia->photo); + assertNull($pollMedia->sticker); + assertNull($pollMedia->venue); + assertNull($pollMedia->video); + } + + public function testFromTelegramResult(): void + { + $pollMedia = (new ObjectFactory())->create([ + 'animation' => [ + 'file_id' => 'animation_file_id', + 'file_unique_id' => 'animation_unique_id', + 'width' => 1280, + 'height' => 720, + 'duration' => 10, + ], + 'audio' => [ + 'file_id' => 'audio_file_id', + 'file_unique_id' => 'audio_unique_id', + 'duration' => 180, + ], + 'document' => [ + 'file_id' => 'document_file_id', + 'file_unique_id' => 'document_unique_id', + ], + 'live_photo' => [ + 'file_id' => 'live_photo_file_id', + 'file_unique_id' => 'live_photo_unique_id', + 'width' => 1080, + 'height' => 1920, + 'duration' => 5, + ], + 'location' => [ + 'latitude' => 55.7558, + 'longitude' => 37.6173, + ], + 'photo' => [ + [ + 'file_id' => 'photo_file_id_1', + 'file_unique_id' => 'photo_unique_id_1', + 'width' => 1920, + 'height' => 1080, + ], + [ + 'file_id' => 'photo_file_id_2', + 'file_unique_id' => 'photo_unique_id_2', + 'width' => 960, + 'height' => 540, + ], + ], + 'sticker' => [ + 'file_id' => 'sticker_file_id', + 'file_unique_id' => 'sticker_unique_id', + 'type' => 'regular', + 'width' => 512, + 'height' => 512, + 'is_animated' => false, + 'is_video' => false, + ], + 'venue' => [ + 'location' => [ + 'latitude' => 55.7558, + 'longitude' => 37.6173, + ], + 'title' => 'Kremlin', + 'address' => 'Red Square, Moscow', + ], + 'video' => [ + 'file_id' => 'video_file_id', + 'file_unique_id' => 'video_unique_id', + 'width' => 1920, + 'height' => 1080, + 'duration' => 30, + ], + ], null, PollMedia::class); + + assertSame('animation_file_id', $pollMedia->animation?->fileId); + assertSame('audio_file_id', $pollMedia->audio?->fileId); + assertSame('document_file_id', $pollMedia->document?->fileId); + assertSame('live_photo_file_id', $pollMedia->livePhoto?->fileId); + assertSame(55.7558, $pollMedia->location?->latitude); + assertCount(2, $pollMedia->photo); + assertSame('photo_file_id_1', $pollMedia->photo[0]->fileId); + assertSame('photo_file_id_2', $pollMedia->photo[1]->fileId); + assertSame('sticker_file_id', $pollMedia->sticker?->fileId); + assertSame('Kremlin', $pollMedia->venue?->title); + assertSame('video_file_id', $pollMedia->video?->fileId); + } +} From 585408db34bb7482958b13a133daee7ea2ed701a Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 09:18:43 +0300 Subject: [PATCH 12/32] Add `explanationMedia` and `media` fields to `Poll` type --- CHANGELOG.md | 1 + src/Type/Poll.php | 2 ++ tests/Type/PollTest.php | 24 ++++++++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9061015..0282360a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - New #199: Add `DeleteMessageReaction` method. - New #199: Add `InputMediaSticker`, `InputMediaVenue` and `InputMediaLocation` types. - New #199: Add `PollMedia` and `LivePhoto` type. +- New #199: Add `explanationMedia` and `media` fields to `Poll` type. ## 0.20 April 26, 2026 diff --git a/src/Type/Poll.php b/src/Type/Poll.php index c6bc57eb..f62ca028 100644 --- a/src/Type/Poll.php +++ b/src/Type/Poll.php @@ -40,10 +40,12 @@ public function __construct( public ?string $explanation = null, #[ArrayOfObjectsValue(MessageEntity::class)] public ?array $explanationEntities = null, + public ?PollMedia $explanationMedia = null, public ?int $openPeriod = null, public ?int $closeDate = null, public ?string $description = null, #[ArrayOfObjectsValue(MessageEntity::class)] public ?array $descriptionEntities = null, + public ?PollMedia $media = null, ) {} } diff --git a/tests/Type/PollTest.php b/tests/Type/PollTest.php index df3f5b40..0a2d6e14 100644 --- a/tests/Type/PollTest.php +++ b/tests/Type/PollTest.php @@ -41,13 +41,16 @@ public function testBase(): void assertSame('regular', $poll->type); assertTrue($poll->allowsMultipleAnswers); assertFalse($poll->allowsRevoting); + assertNull($poll->questionEntities); assertNull($poll->correctOptionIds); assertNull($poll->explanation); assertNull($poll->explanationEntities); + assertNull($poll->explanationMedia); assertNull($poll->openPeriod); assertNull($poll->closeDate); assertNull($poll->description); assertNull($poll->descriptionEntities); + assertNull($poll->media); } public function testFromTelegramResult(): void @@ -90,6 +93,23 @@ public function testFromTelegramResult(): void 'type' => 'bold', ], ], + 'explanation_media' => [ + 'location' => [ + 'latitude' => 55.7558, + 'longitude' => 37.6173, + ], + ], + 'media' => [ + 'sticker' => [ + 'file_id' => 'sticker_file_id', + 'file_unique_id' => 'sticker_unique_id', + 'type' => 'regular', + 'width' => 512, + 'height' => 512, + 'is_animated' => false, + 'is_video' => false, + ], + ], ], null, Poll::class); assertSame('12', $poll->id); @@ -114,10 +134,14 @@ public function testFromTelegramResult(): void assertCount(1, $poll->explanationEntities); assertSame(31, $poll->explanationEntities[0]->length); + assertSame(55.7558, $poll->explanationMedia?->location?->latitude); + assertSame(123, $poll->openPeriod); assertSame(456, $poll->closeDate); assertSame('Poll description', $poll->description); assertCount(1, $poll->descriptionEntities); assertSame(4, $poll->descriptionEntities[0]->length); + + assertSame('sticker_file_id', $poll->media?->sticker?->fileId); } } From 01a5a4e208f4db9723e5f85ccdef66d39d22ed90 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 09:26:56 +0300 Subject: [PATCH 13/32] Add `membersOnly` and `countryCodes` fields to `Poll` type --- CHANGELOG.md | 2 +- src/Type/Poll.php | 5 +++++ tests/Method/UpdatingMessage/StopPollTest.php | 1 + tests/TelegramBotApi/TelegramBotApiTest.php | 1 + tests/Type/ExternalReplyInfoTest.php | 1 + tests/Type/MessageTest.php | 1 + tests/Type/PollTest.php | 8 ++++++++ tests/Type/Update/UpdateTest.php | 1 + 8 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0282360a..b9cbc717 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ - New #199: Add `DeleteMessageReaction` method. - New #199: Add `InputMediaSticker`, `InputMediaVenue` and `InputMediaLocation` types. - New #199: Add `PollMedia` and `LivePhoto` type. -- New #199: Add `explanationMedia` and `media` fields to `Poll` type. +- New #199: Add `explanationMedia`, `media`, `membersOnly` and `countryCodes` fields to `Poll` type. ## 0.20 April 26, 2026 diff --git a/src/Type/Poll.php b/src/Type/Poll.php index f62ca028..8dd9d217 100644 --- a/src/Type/Poll.php +++ b/src/Type/Poll.php @@ -7,6 +7,7 @@ use Phptg\BotApi\ParseResult\ValueProcessor\ArrayMap; use Phptg\BotApi\ParseResult\ValueProcessor\ArrayOfObjectsValue; use Phptg\BotApi\ParseResult\ValueProcessor\IntegerValue; +use Phptg\BotApi\ParseResult\ValueProcessor\StringValue; /** * @see https://core.telegram.org/bots/api#poll @@ -21,6 +22,7 @@ * @param int[]|null $correctOptionIds * @param MessageEntity[]|null $explanationEntities * @param MessageEntity[]|null $descriptionEntities + * @param string[]|null $countryCodes */ public function __construct( public string $id, @@ -33,6 +35,9 @@ public function __construct( public string $type, public bool $allowsMultipleAnswers, public bool $allowsRevoting, + public bool $membersOnly, + #[ArrayMap(StringValue::class)] + public ?array $countryCodes = null, #[ArrayOfObjectsValue(MessageEntity::class)] public ?array $questionEntities = null, #[ArrayMap(IntegerValue::class)] diff --git a/tests/Method/UpdatingMessage/StopPollTest.php b/tests/Method/UpdatingMessage/StopPollTest.php index 9ce26e8e..617a05be 100644 --- a/tests/Method/UpdatingMessage/StopPollTest.php +++ b/tests/Method/UpdatingMessage/StopPollTest.php @@ -62,6 +62,7 @@ public function testPrepareResult(): void 'type' => 'regular', 'allows_multiple_answers' => true, 'allows_revoting' => false, + 'members_only' => true, ])->call($method); assertSame('12', $preparedResult->id); diff --git a/tests/TelegramBotApi/TelegramBotApiTest.php b/tests/TelegramBotApi/TelegramBotApiTest.php index 612d0349..b96f1be2 100644 --- a/tests/TelegramBotApi/TelegramBotApiTest.php +++ b/tests/TelegramBotApi/TelegramBotApiTest.php @@ -2530,6 +2530,7 @@ public function testStopPoll(): void 'type' => 'regular', 'allows_multiple_answers' => true, 'allows_revoting' => false, + 'members_only' => true, ]); $result = $api->stopPoll(1, 2); diff --git a/tests/Type/ExternalReplyInfoTest.php b/tests/Type/ExternalReplyInfoTest.php index b6a79694..7ed3cdc7 100644 --- a/tests/Type/ExternalReplyInfoTest.php +++ b/tests/Type/ExternalReplyInfoTest.php @@ -183,6 +183,7 @@ public function testFromTelegramResult(): void 'type' => 'regular', 'allows_multiple_answers' => true, 'allows_revoting' => false, + 'members_only' => true, ], 'venue' => [ 'location' => [ diff --git a/tests/Type/MessageTest.php b/tests/Type/MessageTest.php index 664900ca..47565a3f 100644 --- a/tests/Type/MessageTest.php +++ b/tests/Type/MessageTest.php @@ -353,6 +353,7 @@ public function testFromTelegramResult(): void 'type' => 'regular', 'allows_multiple_answers' => true, 'allows_revoting' => false, + 'members_only' => true, ], 'venue' => [ 'location' => [ diff --git a/tests/Type/PollTest.php b/tests/Type/PollTest.php index 0a2d6e14..7e39a0b0 100644 --- a/tests/Type/PollTest.php +++ b/tests/Type/PollTest.php @@ -30,6 +30,7 @@ public function testBase(): void 'regular', true, false, + true, ); assertSame('12', $poll->id); @@ -41,6 +42,8 @@ public function testBase(): void assertSame('regular', $poll->type); assertTrue($poll->allowsMultipleAnswers); assertFalse($poll->allowsRevoting); + assertTrue($poll->membersOnly); + assertNull($poll->countryCodes); assertNull($poll->questionEntities); assertNull($poll->correctOptionIds); assertNull($poll->explanation); @@ -67,6 +70,7 @@ public function testFromTelegramResult(): void 'type' => 'regular', 'allows_multiple_answers' => true, 'allows_revoting' => true, + 'members_only' => true, 'question_entities' => [ [ 'offset' => 0, @@ -110,6 +114,7 @@ public function testFromTelegramResult(): void 'is_video' => false, ], ], + 'country_codes' => ['US', 'GB', 'DE'], ], null, Poll::class); assertSame('12', $poll->id); @@ -125,6 +130,9 @@ public function testFromTelegramResult(): void assertTrue($poll->allowsMultipleAnswers); assertTrue($poll->allowsRevoting); + assertTrue($poll->membersOnly); + assertSame(['US', 'GB', 'DE'], $poll->countryCodes); + assertCount(1, $poll->questionEntities); assertSame(35, $poll->questionEntities[0]->length); diff --git a/tests/Type/Update/UpdateTest.php b/tests/Type/Update/UpdateTest.php index 578a8c10..fea61912 100644 --- a/tests/Type/Update/UpdateTest.php +++ b/tests/Type/Update/UpdateTest.php @@ -239,6 +239,7 @@ public function testFromTelegramResult(): void 'type' => 'regular', 'allows_multiple_answers' => false, 'allows_revoting' => true, + 'members_only' => false, ], 'poll_answer' => [ 'poll_id' => 'poll2', From 46d121017eff63ea96075def443ee6342c1df5b1 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 09:29:37 +0300 Subject: [PATCH 14/32] Add `media` field to `PollOption` type --- CHANGELOG.md | 1 + src/Type/PollOption.php | 1 + tests/Type/PollOptionTest.php | 12 ++++++++++++ 3 files changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9cbc717..744aa33d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - New #199: Add `InputMediaSticker`, `InputMediaVenue` and `InputMediaLocation` types. - New #199: Add `PollMedia` and `LivePhoto` type. - New #199: Add `explanationMedia`, `media`, `membersOnly` and `countryCodes` fields to `Poll` type. +- New #199: Add `media` field to `PollOption` type. ## 0.20 April 26, 2026 diff --git a/src/Type/PollOption.php b/src/Type/PollOption.php index 1369a7a6..4d04ca8e 100644 --- a/src/Type/PollOption.php +++ b/src/Type/PollOption.php @@ -22,6 +22,7 @@ public function __construct( public int $voterCount, #[ArrayOfObjectsValue(MessageEntity::class)] public ?array $textEntities = null, + public ?PollMedia $media = null, public ?User $addedByUser = null, public ?Chat $addedByChat = null, public ?int $additionDate = null, diff --git a/tests/Type/PollOptionTest.php b/tests/Type/PollOptionTest.php index 0e31244c..c21f07c7 100644 --- a/tests/Type/PollOptionTest.php +++ b/tests/Type/PollOptionTest.php @@ -22,6 +22,7 @@ public function testBase(): void assertSame('A', $option->text); assertSame(25, $option->voterCount); assertNull($option->textEntities); + assertNull($option->media); assertNull($option->addedByUser); assertNull($option->addedByChat); assertNull($option->additionDate); @@ -40,6 +41,15 @@ public function testFromTelegramResult(): void 'type' => 'bold', ], ], + 'media' => [ + 'video' => [ + 'file_id' => 'video_file_id', + 'file_unique_id' => 'video_unique_id', + 'width' => 1920, + 'height' => 1080, + 'duration' => 30, + ], + ], 'added_by_user' => [ 'id' => 42, 'is_bot' => false, @@ -59,6 +69,8 @@ public function testFromTelegramResult(): void assertCount(1, $option->textEntities); assertSame(23, $option->textEntities[0]->offset); + assertSame('video_file_id', $option->media?->video?->fileId); + assertSame(42, $option->addedByUser->id); assertSame(100, $option->addedByChat->id); assertSame(1700000000, $option->additionDate); From fa643ea068185abffc70c03c4076f24bfb784eea Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 09:47:03 +0300 Subject: [PATCH 15/32] Add `InputPollMedia` and `InputPollOptionMedia` types --- CHANGELOG.md | 1 + src/Type/InputMediaAnimation.php | 2 +- src/Type/InputMediaAudio.php | 2 +- src/Type/InputMediaDocument.php | 2 +- src/Type/InputMediaLocation.php | 2 +- src/Type/InputMediaPhoto.php | 2 +- src/Type/InputMediaSticker.php | 2 +- src/Type/InputMediaVenue.php | 2 +- src/Type/InputMediaVideo.php | 2 +- src/Type/InputPollMedia.php | 22 ++++++++++++++++++++++ src/Type/InputPollOptionMedia.php | 23 +++++++++++++++++++++++ 11 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 src/Type/InputPollMedia.php create mode 100644 src/Type/InputPollOptionMedia.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 744aa33d..8b8cf4cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - New #199: Add `PollMedia` and `LivePhoto` type. - New #199: Add `explanationMedia`, `media`, `membersOnly` and `countryCodes` fields to `Poll` type. - New #199: Add `media` field to `PollOption` type. +- New #199: Add `InputPollMedia` and `InputPollOptionMedia` types. ## 0.20 April 26, 2026 diff --git a/src/Type/InputMediaAnimation.php b/src/Type/InputMediaAnimation.php index 8a833be8..b19a14c1 100644 --- a/src/Type/InputMediaAnimation.php +++ b/src/Type/InputMediaAnimation.php @@ -11,7 +11,7 @@ * * @api */ -final readonly class InputMediaAnimation implements InputMedia +final readonly class InputMediaAnimation implements InputMedia, InputPollMedia, InputPollOptionMedia { /** * @param MessageEntity[]|null $captionEntities diff --git a/src/Type/InputMediaAudio.php b/src/Type/InputMediaAudio.php index 17039be3..1e90bdd4 100644 --- a/src/Type/InputMediaAudio.php +++ b/src/Type/InputMediaAudio.php @@ -11,7 +11,7 @@ * * @api */ -final readonly class InputMediaAudio implements InputMedia +final readonly class InputMediaAudio implements InputMedia, InputPollMedia { /** * @param MessageEntity[]|null $captionEntities diff --git a/src/Type/InputMediaDocument.php b/src/Type/InputMediaDocument.php index 9b1b9dca..d9e97505 100644 --- a/src/Type/InputMediaDocument.php +++ b/src/Type/InputMediaDocument.php @@ -11,7 +11,7 @@ * * @api */ -final readonly class InputMediaDocument implements InputMedia +final readonly class InputMediaDocument implements InputMedia, InputPollMedia { /** * @param MessageEntity[]|null $captionEntities diff --git a/src/Type/InputMediaLocation.php b/src/Type/InputMediaLocation.php index c03363b2..71e7875e 100644 --- a/src/Type/InputMediaLocation.php +++ b/src/Type/InputMediaLocation.php @@ -11,7 +11,7 @@ * * @api */ -final readonly class InputMediaLocation implements InputMedia +final readonly class InputMediaLocation implements InputPollMedia, InputPollOptionMedia { public function __construct( public float $latitude, diff --git a/src/Type/InputMediaPhoto.php b/src/Type/InputMediaPhoto.php index 2cf39fea..19109ef1 100644 --- a/src/Type/InputMediaPhoto.php +++ b/src/Type/InputMediaPhoto.php @@ -11,7 +11,7 @@ * * @api */ -final readonly class InputMediaPhoto implements InputMedia +final readonly class InputMediaPhoto implements InputMedia, InputPollMedia, InputPollOptionMedia { /** * @param MessageEntity[]|null $captionEntities diff --git a/src/Type/InputMediaSticker.php b/src/Type/InputMediaSticker.php index 8920f111..d906effa 100644 --- a/src/Type/InputMediaSticker.php +++ b/src/Type/InputMediaSticker.php @@ -11,7 +11,7 @@ * * @api */ -final readonly class InputMediaSticker implements InputMedia +final readonly class InputMediaSticker implements InputPollOptionMedia { public function __construct( public string|InputFile $media, diff --git a/src/Type/InputMediaVenue.php b/src/Type/InputMediaVenue.php index 033df4af..c2dd7fb1 100644 --- a/src/Type/InputMediaVenue.php +++ b/src/Type/InputMediaVenue.php @@ -11,7 +11,7 @@ * * @api */ -final readonly class InputMediaVenue implements InputMedia +final readonly class InputMediaVenue implements InputPollMedia, InputPollOptionMedia { public function __construct( public float $latitude, diff --git a/src/Type/InputMediaVideo.php b/src/Type/InputMediaVideo.php index ce171c1a..3b74b2e9 100644 --- a/src/Type/InputMediaVideo.php +++ b/src/Type/InputMediaVideo.php @@ -11,7 +11,7 @@ * * @api */ -final readonly class InputMediaVideo implements InputMedia +final readonly class InputMediaVideo implements InputMedia, InputPollMedia, InputPollOptionMedia { /** * @param MessageEntity[]|null $captionEntities diff --git a/src/Type/InputPollMedia.php b/src/Type/InputPollMedia.php new file mode 100644 index 00000000..92d6916f --- /dev/null +++ b/src/Type/InputPollMedia.php @@ -0,0 +1,22 @@ + + */ + public function toRequestArray(?FileCollector $fileCollector = null): array; +} diff --git a/src/Type/InputPollOptionMedia.php b/src/Type/InputPollOptionMedia.php new file mode 100644 index 00000000..2225e72d --- /dev/null +++ b/src/Type/InputPollOptionMedia.php @@ -0,0 +1,23 @@ + + */ + public function toRequestArray(?FileCollector $fileCollector = null): array; +} + From d0fb5d74e0d7e5b216c656b1fad47ba62c99542a Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 09:51:51 +0300 Subject: [PATCH 16/32] Fix psalm --- src/Type/InputMediaAnimation.php | 3 +++ src/Type/InputMediaAudio.php | 3 +++ src/Type/InputMediaDocument.php | 3 +++ src/Type/InputMediaLocation.php | 3 +++ src/Type/InputMediaPhoto.php | 3 +++ src/Type/InputMediaVenue.php | 3 +++ src/Type/InputMediaVideo.php | 3 +++ 7 files changed, 21 insertions(+) diff --git a/src/Type/InputMediaAnimation.php b/src/Type/InputMediaAnimation.php index b19a14c1..12da263f 100644 --- a/src/Type/InputMediaAnimation.php +++ b/src/Type/InputMediaAnimation.php @@ -34,6 +34,9 @@ public function getType(): string return 'animation'; } + /** + * @return array + */ public function toRequestArray(?FileCollector $fileCollector = null): array { if ($fileCollector !== null) { diff --git a/src/Type/InputMediaAudio.php b/src/Type/InputMediaAudio.php index 1e90bdd4..2d550598 100644 --- a/src/Type/InputMediaAudio.php +++ b/src/Type/InputMediaAudio.php @@ -32,6 +32,9 @@ public function getType(): string return 'audio'; } + /** + * @return array + */ public function toRequestArray(?FileCollector $fileCollector = null): array { if ($fileCollector !== null) { diff --git a/src/Type/InputMediaDocument.php b/src/Type/InputMediaDocument.php index d9e97505..72c9fd3a 100644 --- a/src/Type/InputMediaDocument.php +++ b/src/Type/InputMediaDocument.php @@ -30,6 +30,9 @@ public function getType(): string return 'document'; } + /** + * @return array + */ public function toRequestArray(?FileCollector $fileCollector = null): array { if ($fileCollector !== null) { diff --git a/src/Type/InputMediaLocation.php b/src/Type/InputMediaLocation.php index 71e7875e..67d11b1b 100644 --- a/src/Type/InputMediaLocation.php +++ b/src/Type/InputMediaLocation.php @@ -24,6 +24,9 @@ public function getType(): string return 'location'; } + /** + * @return array + */ public function toRequestArray(?FileCollector $fileCollector = null): array { return array_filter( diff --git a/src/Type/InputMediaPhoto.php b/src/Type/InputMediaPhoto.php index 19109ef1..c81d5851 100644 --- a/src/Type/InputMediaPhoto.php +++ b/src/Type/InputMediaPhoto.php @@ -30,6 +30,9 @@ public function getType(): string return 'photo'; } + /** + * @return array + */ public function toRequestArray(?FileCollector $fileCollector = null): array { if ($fileCollector !== null) { diff --git a/src/Type/InputMediaVenue.php b/src/Type/InputMediaVenue.php index c2dd7fb1..81d96cbf 100644 --- a/src/Type/InputMediaVenue.php +++ b/src/Type/InputMediaVenue.php @@ -29,6 +29,9 @@ public function getType(): string return 'venue'; } + /** + * @return array + */ public function toRequestArray(?FileCollector $fileCollector = null): array { return array_filter( diff --git a/src/Type/InputMediaVideo.php b/src/Type/InputMediaVideo.php index 3b74b2e9..acff6459 100644 --- a/src/Type/InputMediaVideo.php +++ b/src/Type/InputMediaVideo.php @@ -37,6 +37,9 @@ public function getType(): string return 'video'; } + /** + * @return array + */ public function toRequestArray(?FileCollector $fileCollector = null): array { if ($fileCollector !== null) { From a1242c507fd39ea099d222985f94bd1076d9d3e9 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 10:21:29 +0300 Subject: [PATCH 17/32] Add `explanationMedia`, `media`, `membersOnly` and `countryCodes` parameters to `SendPoll` method --- CHANGELOG.md | 1 + src/Method/SendPoll.php | 10 ++++++++++ src/TelegramBotApi.php | 10 ++++++++++ src/Type/InputPollOptionMedia.php | 1 - tests/Method/SendPollTest.php | 11 +++++++++++ tests/Type/PollMediaTest.php | 2 -- 6 files changed, 32 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b8cf4cb..e5631f00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - New #199: Add `explanationMedia`, `media`, `membersOnly` and `countryCodes` fields to `Poll` type. - New #199: Add `media` field to `PollOption` type. - New #199: Add `InputPollMedia` and `InputPollOptionMedia` types. +- New #199: Add `explanationMedia`, `media`, `membersOnly` and `countryCodes` parameters to `SendPoll` method. ## 0.20 April 26, 2026 diff --git a/src/Method/SendPoll.php b/src/Method/SendPoll.php index ac9c6933..d825f21a 100644 --- a/src/Method/SendPoll.php +++ b/src/Method/SendPoll.php @@ -10,6 +10,7 @@ use Phptg\BotApi\MethodInterface; use Phptg\BotApi\Type\ForceReply; use Phptg\BotApi\Type\InlineKeyboardMarkup; +use Phptg\BotApi\Type\InputPollMedia; use Phptg\BotApi\Type\InputPollOption; use Phptg\BotApi\Type\Message; use Phptg\BotApi\Type\MessageEntity; @@ -30,6 +31,7 @@ * @param int[]|null $correctOptionIds * @param MessageEntity[]|null $explanationEntities * @param MessageEntity[]|null $descriptionEntities + * @param string[]|null $countryCodes */ public function __construct( private int|string $chatId, @@ -46,9 +48,11 @@ public function __construct( private ?string $explanation = null, private ?string $explanationParseMode = null, private ?array $explanationEntities = null, + private ?InputPollMedia $explanationMedia = null, private ?int $openPeriod = null, private ?DateTimeImmutable $closeDate = null, private ?bool $isClosed = null, + private ?InputPollMedia $media = null, private ?bool $disableNotification = null, private ?bool $protectContent = null, private ?string $messageEffectId = null, @@ -59,6 +63,8 @@ public function __construct( private ?bool $shuffleOptions = null, private ?bool $allowAddingOptions = null, private ?bool $hideResultsUntilCloses = null, + private ?bool $membersOnly = null, + private ?array $countryCodes = null, private ?string $description = null, private ?string $descriptionParseMode = null, private ?array $descriptionEntities = null, @@ -100,6 +106,8 @@ public function getData(): array 'shuffle_options' => $this->shuffleOptions, 'allow_adding_options' => $this->allowAddingOptions, 'hide_results_until_closes' => $this->hideResultsUntilCloses, + 'members_only' => $this->membersOnly, + 'country_codes' => $this->countryCodes, 'correct_option_ids' => $this->correctOptionIds, 'explanation' => $this->explanation, 'explanation_parse_mode' => $this->explanationParseMode, @@ -109,6 +117,7 @@ public function getData(): array static fn(MessageEntity $entity) => $entity->toRequestArray(), $this->explanationEntities, ), + 'explanation_media' => $this->explanationMedia?->toRequestArray(), 'open_period' => $this->openPeriod, 'close_date' => $this->closeDate?->getTimestamp(), 'is_closed' => $this->isClosed, @@ -120,6 +129,7 @@ public function getData(): array static fn(MessageEntity $entity) => $entity->toRequestArray(), $this->descriptionEntities, ), + 'media' => $this->media?->toRequestArray(), 'disable_notification' => $this->disableNotification, 'protect_content' => $this->protectContent, 'allow_paid_broadcast' => $this->allowPaidBroadcast, diff --git a/src/TelegramBotApi.php b/src/TelegramBotApi.php index efe8361f..f3371ad0 100644 --- a/src/TelegramBotApi.php +++ b/src/TelegramBotApi.php @@ -216,6 +216,7 @@ use Phptg\BotApi\Type\InputMediaPhoto; use Phptg\BotApi\Type\InputMediaVideo; use Phptg\BotApi\Type\InputPaidMedia; +use Phptg\BotApi\Type\InputPollMedia; use Phptg\BotApi\Type\InputPollOption; use Phptg\BotApi\Type\InputProfilePhoto; use Phptg\BotApi\Type\InputStoryContent; @@ -2549,6 +2550,7 @@ public function sendPhoto( * @param int[]|null $correctOptionIds * @param MessageEntity[]|null $explanationEntities * @param MessageEntity[]|null $descriptionEntities + * @param string[]|null $countryCodes * * @see https://core.telegram.org/bots/api#sendpoll */ @@ -2567,9 +2569,11 @@ public function sendPoll( ?string $explanation = null, ?string $explanationParseMode = null, ?array $explanationEntities = null, + ?InputPollMedia $explanationMedia = null, ?int $openPeriod = null, ?DateTimeImmutable $closeDate = null, ?bool $isClosed = null, + ?InputPollMedia $media = null, ?bool $disableNotification = null, ?bool $protectContent = null, ?string $messageEffectId = null, @@ -2580,6 +2584,8 @@ public function sendPoll( ?bool $shuffleOptions = null, ?bool $allowAddingOptions = null, ?bool $hideResultsUntilCloses = null, + ?bool $membersOnly = null, + ?array $countryCodes = null, ?string $description = null, ?string $descriptionParseMode = null, ?array $descriptionEntities = null, @@ -2600,9 +2606,11 @@ public function sendPoll( $explanation, $explanationParseMode, $explanationEntities, + $explanationMedia, $openPeriod, $closeDate, $isClosed, + $media, $disableNotification, $protectContent, $messageEffectId, @@ -2613,6 +2621,8 @@ public function sendPoll( $shuffleOptions, $allowAddingOptions, $hideResultsUntilCloses, + $membersOnly, + $countryCodes, $description, $descriptionParseMode, $descriptionEntities, diff --git a/src/Type/InputPollOptionMedia.php b/src/Type/InputPollOptionMedia.php index 2225e72d..37effced 100644 --- a/src/Type/InputPollOptionMedia.php +++ b/src/Type/InputPollOptionMedia.php @@ -20,4 +20,3 @@ public function getType(): string; */ public function toRequestArray(?FileCollector $fileCollector = null): array; } - diff --git a/tests/Method/SendPollTest.php b/tests/Method/SendPollTest.php index bf0e555b..59fcd1d6 100644 --- a/tests/Method/SendPollTest.php +++ b/tests/Method/SendPollTest.php @@ -10,6 +10,7 @@ use Phptg\BotApi\Transport\HttpMethod; use Phptg\BotApi\Tests\Support\TestHelper; use Phptg\BotApi\Type\ForceReply; +use Phptg\BotApi\Type\InputMediaPhoto; use Phptg\BotApi\Type\InputPollOption; use Phptg\BotApi\Type\MessageEntity; use Phptg\BotApi\Type\ReplyParameters; @@ -49,6 +50,8 @@ public function testFull(): void $date = new DateTimeImmutable(); $replyParameters = new ReplyParameters(23); $replyMarkup = new ForceReply(); + $explanationMedia = new InputMediaPhoto('file_id1'); + $pollMedia = new InputMediaPhoto('file_id2'); $method = new SendPoll( 12, 'How are you?', @@ -64,9 +67,11 @@ public function testFull(): void 'Good explanation', 'Markdown', [$messageEntity2], + $explanationMedia, 300, $date, true, + $pollMedia, false, false, 'meid2', @@ -77,6 +82,8 @@ public function testFull(): void true, true, true, + false, + ['US', 'GB'], 'Poll description', 'HTML', [$messageEntity3], @@ -103,16 +110,20 @@ public function testFull(): void 'shuffle_options' => true, 'allow_adding_options' => true, 'hide_results_until_closes' => true, + 'members_only' => false, + 'country_codes' => ['US', 'GB'], 'correct_option_ids' => [0, 1], 'explanation' => 'Good explanation', 'explanation_parse_mode' => 'Markdown', 'explanation_entities' => [$messageEntity2->toRequestArray()], + 'explanation_media' => $explanationMedia->toRequestArray(), 'open_period' => 300, 'close_date' => $date->getTimestamp(), 'is_closed' => true, 'description' => 'Poll description', 'description_parse_mode' => 'HTML', 'description_entities' => [$messageEntity3->toRequestArray()], + 'media' => $pollMedia->toRequestArray(), 'disable_notification' => false, 'protect_content' => false, 'allow_paid_broadcast' => true, diff --git a/tests/Type/PollMediaTest.php b/tests/Type/PollMediaTest.php index ec456d66..b88cc376 100644 --- a/tests/Type/PollMediaTest.php +++ b/tests/Type/PollMediaTest.php @@ -7,8 +7,6 @@ use PHPUnit\Framework\TestCase; use Phptg\BotApi\ParseResult\ObjectFactory; use Phptg\BotApi\Type\PollMedia; -use Phptg\BotApi\Type\Location; -use Phptg\BotApi\Type\Sticker\Sticker; use function PHPUnit\Framework\assertCount; use function PHPUnit\Framework\assertNull; From 7821d649100385c6c6c154f3e9a35b2a1bc39192 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 13:25:05 +0300 Subject: [PATCH 18/32] Add `media` field to `InputPollOption` type --- CHANGELOG.md | 1 + src/Method/SendPoll.php | 19 +++++++++++++------ src/Type/InputPollOption.php | 6 +++++- tests/Method/SendPollTest.php | 19 +++++++++++++------ tests/Type/InputPollOptionTest.php | 7 ++++++- 5 files changed, 38 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5631f00..1d671396 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - New #199: Add `media` field to `PollOption` type. - New #199: Add `InputPollMedia` and `InputPollOptionMedia` types. - New #199: Add `explanationMedia`, `media`, `membersOnly` and `countryCodes` parameters to `SendPoll` method. +- New #199: Add `media` field to `InputPollOption` type. ## 0.20 April 26, 2026 diff --git a/src/Method/SendPoll.php b/src/Method/SendPoll.php index d825f21a..5feb5355 100644 --- a/src/Method/SendPoll.php +++ b/src/Method/SendPoll.php @@ -5,6 +5,7 @@ namespace Phptg\BotApi\Method; use DateTimeImmutable; +use Phptg\BotApi\FileCollector; use Phptg\BotApi\ParseResult\ValueProcessor\ObjectValue; use Phptg\BotApi\Transport\HttpMethod; use Phptg\BotApi\MethodInterface; @@ -82,6 +83,14 @@ public function getApiMethod(): string public function getData(): array { + $fileCollector = new FileCollector(); + $options = array_map( + static fn(InputPollOption $option) => $option->toRequestArray($fileCollector), + $this->options, + ); + $explanationMedia = $this->explanationMedia?->toRequestArray($fileCollector); + $media = $this->media?->toRequestArray($fileCollector); + return array_filter( [ 'business_connection_id' => $this->businessConnectionId, @@ -95,10 +104,7 @@ public function getData(): array static fn(MessageEntity $entity) => $entity->toRequestArray(), $this->questionEntities, ), - 'options' => array_map( - static fn(InputPollOption $option) => $option->toRequestArray(), - $this->options, - ), + 'options' => $options, 'is_anonymous' => $this->isAnonymous, 'type' => $this->type, 'allows_multiple_answers' => $this->allowsMultipleAnswers, @@ -117,7 +123,7 @@ public function getData(): array static fn(MessageEntity $entity) => $entity->toRequestArray(), $this->explanationEntities, ), - 'explanation_media' => $this->explanationMedia?->toRequestArray(), + 'explanation_media' => $explanationMedia, 'open_period' => $this->openPeriod, 'close_date' => $this->closeDate?->getTimestamp(), 'is_closed' => $this->isClosed, @@ -129,13 +135,14 @@ public function getData(): array static fn(MessageEntity $entity) => $entity->toRequestArray(), $this->descriptionEntities, ), - 'media' => $this->media?->toRequestArray(), + 'media' => $media, 'disable_notification' => $this->disableNotification, 'protect_content' => $this->protectContent, 'allow_paid_broadcast' => $this->allowPaidBroadcast, 'message_effect_id' => $this->messageEffectId, 'reply_parameters' => $this->replyParameters?->toRequestArray(), 'reply_markup' => $this->replyMarkup?->toRequestArray(), + ...$fileCollector->get(), ], static fn(mixed $value): bool => $value !== null, ); diff --git a/src/Type/InputPollOption.php b/src/Type/InputPollOption.php index 7c219724..98d7c33a 100644 --- a/src/Type/InputPollOption.php +++ b/src/Type/InputPollOption.php @@ -4,6 +4,8 @@ namespace Phptg\BotApi\Type; +use Phptg\BotApi\FileCollector; + /** * @see https://core.telegram.org/bots/api#inputpolloption * @@ -18,9 +20,10 @@ public function __construct( public ?string $text = null, public ?string $textParseMode = null, public ?array $textEntities = null, + public ?InputPollOptionMedia $media = null, ) {} - public function toRequestArray(): array + public function toRequestArray(?FileCollector $fileCollector = null): array { return array_filter( [ @@ -32,6 +35,7 @@ public function toRequestArray(): array static fn(MessageEntity $entity) => $entity->toRequestArray(), $this->textEntities, ), + 'media' => $this->media?->toRequestArray($fileCollector), ], static fn(mixed $value): bool => $value !== null, ); diff --git a/tests/Method/SendPollTest.php b/tests/Method/SendPollTest.php index 59fcd1d6..d3499f48 100644 --- a/tests/Method/SendPollTest.php +++ b/tests/Method/SendPollTest.php @@ -10,6 +10,7 @@ use Phptg\BotApi\Transport\HttpMethod; use Phptg\BotApi\Tests\Support\TestHelper; use Phptg\BotApi\Type\ForceReply; +use Phptg\BotApi\Type\InputFile; use Phptg\BotApi\Type\InputMediaPhoto; use Phptg\BotApi\Type\InputPollOption; use Phptg\BotApi\Type\MessageEntity; @@ -42,7 +43,10 @@ public function testBase(): void public function testFull(): void { - $option1 = new InputPollOption('OK'); + $optionFile = new InputFile(null); + $explanationFile = new InputFile(null); + $pollFile = new InputFile(null); + $option1 = new InputPollOption('OK', media: new InputMediaPhoto($optionFile)); $option2 = new InputPollOption('Bad'); $messageEntity1 = new MessageEntity('bold', 0, 5); $messageEntity2 = new MessageEntity('bold', 1, 3); @@ -50,8 +54,8 @@ public function testFull(): void $date = new DateTimeImmutable(); $replyParameters = new ReplyParameters(23); $replyMarkup = new ForceReply(); - $explanationMedia = new InputMediaPhoto('file_id1'); - $pollMedia = new InputMediaPhoto('file_id2'); + $explanationMedia = new InputMediaPhoto($explanationFile); + $pollMedia = new InputMediaPhoto($pollFile); $method = new SendPoll( 12, 'How are you?', @@ -100,7 +104,7 @@ public function testFull(): void 'question_parse_mode' => 'HTML', 'question_entities' => [$messageEntity1->toRequestArray()], 'options' => [ - ['text' => 'OK'], + ['text' => 'OK', 'media' => ['type' => 'photo', 'media' => 'attach://file0']], ['text' => 'Bad'], ], 'is_anonymous' => true, @@ -116,20 +120,23 @@ public function testFull(): void 'explanation' => 'Good explanation', 'explanation_parse_mode' => 'Markdown', 'explanation_entities' => [$messageEntity2->toRequestArray()], - 'explanation_media' => $explanationMedia->toRequestArray(), + 'explanation_media' => ['type' => 'photo', 'media' => 'attach://file1'], 'open_period' => 300, 'close_date' => $date->getTimestamp(), 'is_closed' => true, 'description' => 'Poll description', 'description_parse_mode' => 'HTML', 'description_entities' => [$messageEntity3->toRequestArray()], - 'media' => $pollMedia->toRequestArray(), + 'media' => ['type' => 'photo', 'media' => 'attach://file2'], 'disable_notification' => false, 'protect_content' => false, 'allow_paid_broadcast' => true, 'message_effect_id' => 'meid2', 'reply_parameters' => $replyParameters->toRequestArray(), 'reply_markup' => $replyMarkup->toRequestArray(), + 'file0' => $optionFile, + 'file1' => $explanationFile, + 'file2' => $pollFile, ], $method->getData(), ); diff --git a/tests/Type/InputPollOptionTest.php b/tests/Type/InputPollOptionTest.php index 3f208343..6951bc64 100644 --- a/tests/Type/InputPollOptionTest.php +++ b/tests/Type/InputPollOptionTest.php @@ -5,6 +5,7 @@ namespace Phptg\BotApi\Tests\Type; use PHPUnit\Framework\TestCase; +use Phptg\BotApi\Type\InputMediaPhoto; use Phptg\BotApi\Type\InputPollOption; use Phptg\BotApi\Type\MessageEntity; @@ -20,6 +21,7 @@ public function testBase(): void assertNull($option->text); assertNull($option->textParseMode); assertNull($option->textEntities); + assertNull($option->media); assertSame([], $option->toRequestArray()); } @@ -27,17 +29,20 @@ public function testBase(): void public function testFilled(): void { $messageEntity = new MessageEntity('bold', 0, 4); - $option = new InputPollOption('test', 'MarkdownV2', [$messageEntity]); + $media = new InputMediaPhoto('file_id1'); + $option = new InputPollOption('test', 'MarkdownV2', [$messageEntity], $media); assertSame('test', $option->text); assertSame('MarkdownV2', $option->textParseMode); assertSame([$messageEntity], $option->textEntities); + assertSame($media, $option->media); assertSame( [ 'text' => 'test', 'text_parse_mode' => 'MarkdownV2', 'text_entities' => [$messageEntity->toRequestArray()], + 'media' => $media->toRequestArray(), ], $option->toRequestArray(), ); From 1a171fe36196b73399d428894c384e29c902c479 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 13:32:21 +0300 Subject: [PATCH 19/32] Add `InputMediaLivePhoto` type --- CHANGELOG.md | 2 +- src/Type/InputMediaLivePhoto.php | 68 +++++++++++++++++++++ tests/Type/InputMediaLivePhotoTest.php | 84 ++++++++++++++++++++++++++ 3 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 src/Type/InputMediaLivePhoto.php create mode 100644 tests/Type/InputMediaLivePhotoTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d671396..a3a00692 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ - New #199: Add `returnBots` parameter to `GetChatAdministrators` method. - New #199: Add `DeleteAllMessageReactions` method. - New #199: Add `DeleteMessageReaction` method. -- New #199: Add `InputMediaSticker`, `InputMediaVenue` and `InputMediaLocation` types. +- New #199: Add `InputMediaSticker`, `InputMediaVenue`, `InputMediaLocation` and `InputMediaLivePhoto` types. - New #199: Add `PollMedia` and `LivePhoto` type. - New #199: Add `explanationMedia`, `media`, `membersOnly` and `countryCodes` fields to `Poll` type. - New #199: Add `media` field to `PollOption` type. diff --git a/src/Type/InputMediaLivePhoto.php b/src/Type/InputMediaLivePhoto.php new file mode 100644 index 00000000..edc50d35 --- /dev/null +++ b/src/Type/InputMediaLivePhoto.php @@ -0,0 +1,68 @@ + + */ + public function toRequestArray(?FileCollector $fileCollector = null): array + { + if ($fileCollector !== null) { + $media = $this->media instanceof InputFile + ? 'attach://' . $fileCollector->add($this->media) + : $this->media; + $photo = $this->photo instanceof InputFile + ? 'attach://' . $fileCollector->add($this->photo) + : $this->photo; + } else { + $media = $this->media; + $photo = $this->photo; + } + + return array_filter( + [ + 'type' => $this->getType(), + 'media' => $media, + 'photo' => $photo, + 'caption' => $this->caption, + 'parse_mode' => $this->parseMode, + 'caption_entities' => $this->captionEntities === null ? null : array_map( + static fn(MessageEntity $entity) => $entity->toRequestArray(), + $this->captionEntities, + ), + 'show_caption_above_media' => $this->showCaptionAboveMedia, + 'has_spoiler' => $this->hasSpoiler, + ], + static fn(mixed $value): bool => $value !== null, + ); + } +} diff --git a/tests/Type/InputMediaLivePhotoTest.php b/tests/Type/InputMediaLivePhotoTest.php new file mode 100644 index 00000000..247bbd42 --- /dev/null +++ b/tests/Type/InputMediaLivePhotoTest.php @@ -0,0 +1,84 @@ +getType()); + assertSame( + [ + 'type' => 'live_photo', + 'media' => 'https://example.com/video.mp4', + 'photo' => 'https://example.com/photo.jpg', + ], + $inputMedia->toRequestArray(), + ); + + $fileCollector = new FileCollector(); + assertSame( + [ + 'type' => 'live_photo', + 'media' => 'https://example.com/video.mp4', + 'photo' => 'https://example.com/photo.jpg', + ], + $inputMedia->toRequestArray($fileCollector), + ); + assertEmpty($fileCollector->get()); + } + + public function testFull(): void + { + $mediaFile = new InputFile(null); + $photoFile = new InputFile(null); + $entity = new MessageEntity('bold', 0, 4); + $inputMedia = new InputMediaLivePhoto( + $mediaFile, + $photoFile, + 'Hello', + 'HTML', + [$entity], + false, + true, + ); + + $fileCollector = new FileCollector(); + assertSame( + [ + 'type' => 'live_photo', + 'media' => 'attach://file0', + 'photo' => 'attach://file1', + 'caption' => 'Hello', + 'parse_mode' => 'HTML', + 'caption_entities' => [$entity->toRequestArray()], + 'show_caption_above_media' => false, + 'has_spoiler' => true, + ], + $inputMedia->toRequestArray($fileCollector), + ); + assertSame( + [ + 'file0' => $mediaFile, + 'file1' => $photoFile, + ], + $fileCollector->get(), + ); + } +} From 0ebff8987bebe039746c7b5a088960367a81bfea Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 13:35:19 +0300 Subject: [PATCH 20/32] Add `live_photo` field to `Message` and `ExternalReplyInfo` types --- CHANGELOG.md | 1 + src/Type/ExternalReplyInfo.php | 1 + src/Type/Message.php | 1 + tests/Type/ExternalReplyInfoTest.php | 12 ++++++++++++ tests/Type/MessageTest.php | 12 ++++++++++++ 5 files changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3a00692..84ab5335 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - New #199: Add `explanationMedia`, `media`, `membersOnly` and `countryCodes` fields to `Poll` type. - New #199: Add `media` field to `PollOption` type. - New #199: Add `InputPollMedia` and `InputPollOptionMedia` types. +- New #199: Add `live_photo` field to `Message` and `ExternalReplyInfo` types. - New #199: Add `explanationMedia`, `media`, `membersOnly` and `countryCodes` parameters to `SendPoll` method. - New #199: Add `media` field to `InputPollOption` type. diff --git a/src/Type/ExternalReplyInfo.php b/src/Type/ExternalReplyInfo.php index 3681e531..4983db90 100644 --- a/src/Type/ExternalReplyInfo.php +++ b/src/Type/ExternalReplyInfo.php @@ -27,6 +27,7 @@ public function __construct( public ?Animation $animation = null, public ?Audio $audio = null, public ?Document $document = null, + public ?LivePhoto $livePhoto = null, #[ArrayOfObjectsValue(PhotoSize::class)] public ?array $photo = null, public ?Sticker $sticker = null, diff --git a/src/Type/Message.php b/src/Type/Message.php index 0d35a7a0..0ca89a60 100644 --- a/src/Type/Message.php +++ b/src/Type/Message.php @@ -64,6 +64,7 @@ public function __construct( public ?Animation $animation = null, public ?Audio $audio = null, public ?Document $document = null, + public ?LivePhoto $livePhoto = null, #[ArrayOfObjectsValue(PhotoSize::class)] public ?array $photo = null, public ?Sticker $sticker = null, diff --git a/tests/Type/ExternalReplyInfoTest.php b/tests/Type/ExternalReplyInfoTest.php index 7ed3cdc7..bffd8cb1 100644 --- a/tests/Type/ExternalReplyInfoTest.php +++ b/tests/Type/ExternalReplyInfoTest.php @@ -35,6 +35,7 @@ public function testBase(): void assertNull($externalReplyInfo->animation); assertNull($externalReplyInfo->audio); assertNull($externalReplyInfo->document); + assertNull($externalReplyInfo->livePhoto); assertNull($externalReplyInfo->photo); assertNull($externalReplyInfo->sticker); assertNull($externalReplyInfo->story); @@ -91,6 +92,13 @@ public function testFromTelegramResult(): void 'file_id' => 'f3', 'file_unique_id' => 'fu3', ], + 'live_photo' => [ + 'file_id' => 'f3lp', + 'file_unique_id' => 'fu3lp', + 'width' => 640, + 'height' => 480, + 'duration' => 3, + ], 'photo' => [ [ 'file_id' => 'f4', @@ -220,6 +228,10 @@ public function testFromTelegramResult(): void assertSame('f1', $externalReplyInfo->animation?->fileId); assertSame('f2', $externalReplyInfo->audio?->fileId); assertSame('f3', $externalReplyInfo->document?->fileId); + assertSame('f3lp', $externalReplyInfo->livePhoto?->fileId); + assertSame(640, $externalReplyInfo->livePhoto?->width); + assertSame(480, $externalReplyInfo->livePhoto?->height); + assertSame(3, $externalReplyInfo->livePhoto?->duration); assertCount(1, $externalReplyInfo->photo); assertSame('f4', $externalReplyInfo->photo[0]->fileId); diff --git a/tests/Type/MessageTest.php b/tests/Type/MessageTest.php index 47565a3f..aafd4dee 100644 --- a/tests/Type/MessageTest.php +++ b/tests/Type/MessageTest.php @@ -76,6 +76,7 @@ public function testBase(): void assertNull($message->animation); assertNull($message->audio); assertNull($message->document); + assertNull($message->livePhoto); assertNull($message->photo); assertNull($message->sticker); assertNull($message->story); @@ -278,6 +279,13 @@ public function testFromTelegramResult(): void 'file_id' => 'f3', 'file_unique_id' => 'fu3', ], + 'live_photo' => [ + 'file_id' => 'f3lp', + 'file_unique_id' => 'fu3lp', + 'width' => 640, + 'height' => 480, + 'duration' => 3, + ], 'photo' => [ [ 'file_id' => 'f4', @@ -732,6 +740,10 @@ public function testFromTelegramResult(): void assertSame('an1', $message->animation?->fileId); assertSame('f2', $message->audio?->fileId); assertSame('f3', $message->document?->fileId); + assertSame('f3lp', $message->livePhoto?->fileId); + assertSame(640, $message->livePhoto?->width); + assertSame(480, $message->livePhoto?->height); + assertSame(3, $message->livePhoto?->duration); assertCount(1, $message->photo); assertSame('f4', $message->photo[0]->fileId); From fa0aa3e1550f956aec0eefc23c85709c8404bca7 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 13:42:55 +0300 Subject: [PATCH 21/32] Add `SendLivePhoto` method --- CHANGELOG.md | 1 + src/Method/SendLivePhoto.php | 107 +++++++++++++++++ src/TelegramBotApi.php | 50 ++++++++ tests/Method/SendLivePhotoTest.php | 120 ++++++++++++++++++++ tests/TelegramBotApi/TelegramBotApiTest.php | 17 +++ 5 files changed, 295 insertions(+) create mode 100644 src/Method/SendLivePhoto.php create mode 100644 tests/Method/SendLivePhotoTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 84ab5335..c6ec2c79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - New #199: Add `media` field to `PollOption` type. - New #199: Add `InputPollMedia` and `InputPollOptionMedia` types. - New #199: Add `live_photo` field to `Message` and `ExternalReplyInfo` types. +- New #199: Add `SendLivePhoto` method. - New #199: Add `explanationMedia`, `media`, `membersOnly` and `countryCodes` parameters to `SendPoll` method. - New #199: Add `media` field to `InputPollOption` type. diff --git a/src/Method/SendLivePhoto.php b/src/Method/SendLivePhoto.php new file mode 100644 index 00000000..34327af5 --- /dev/null +++ b/src/Method/SendLivePhoto.php @@ -0,0 +1,107 @@ + + */ +final readonly class SendLivePhoto implements MethodInterface +{ + /** + * @param MessageEntity[]|null $captionEntities + */ + public function __construct( + private int|string $chatId, + private string|InputFile $livePhoto, + private string|InputFile $photo, + private ?string $businessConnectionId = null, + private ?int $messageThreadId = null, + private ?int $directMessagesTopicId = null, + private ?string $caption = null, + private ?string $parseMode = null, + private ?array $captionEntities = null, + private ?bool $showCaptionAboveMedia = null, + private ?bool $hasSpoiler = null, + private ?bool $disableNotification = null, + private ?bool $protectContent = null, + private ?bool $allowPaidBroadcast = null, + private ?string $messageEffectId = null, + private ?SuggestedPostParameters $suggestedPostParameters = null, + private ?ReplyParameters $replyParameters = null, + private InlineKeyboardMarkup|ReplyKeyboardMarkup|ReplyKeyboardRemove|ForceReply|null $replyMarkup = null, + ) {} + + public function getHttpMethod(): HttpMethod + { + return HttpMethod::POST; + } + + public function getApiMethod(): string + { + return 'sendLivePhoto'; + } + + public function getData(): array + { + $fileCollector = new FileCollector(); + $livePhoto = $this->livePhoto instanceof InputFile + ? 'attach://' . $fileCollector->add($this->livePhoto) + : $this->livePhoto; + $photo = $this->photo instanceof InputFile + ? 'attach://' . $fileCollector->add($this->photo) + : $this->photo; + + return array_filter( + [ + 'business_connection_id' => $this->businessConnectionId, + 'chat_id' => $this->chatId, + 'message_thread_id' => $this->messageThreadId, + 'direct_messages_topic_id' => $this->directMessagesTopicId, + 'live_photo' => $livePhoto, + 'photo' => $photo, + 'caption' => $this->caption, + 'parse_mode' => $this->parseMode, + 'caption_entities' => $this->captionEntities === null + ? null + : array_map( + static fn(MessageEntity $entity) => $entity->toRequestArray(), + $this->captionEntities, + ), + 'show_caption_above_media' => $this->showCaptionAboveMedia, + 'has_spoiler' => $this->hasSpoiler, + 'disable_notification' => $this->disableNotification, + 'protect_content' => $this->protectContent, + 'allow_paid_broadcast' => $this->allowPaidBroadcast, + 'message_effect_id' => $this->messageEffectId, + 'suggested_post_parameters' => $this->suggestedPostParameters?->toRequestArray(), + 'reply_parameters' => $this->replyParameters?->toRequestArray(), + 'reply_markup' => $this->replyMarkup?->toRequestArray(), + ...$fileCollector->get(), + ], + static fn(mixed $value): bool => $value !== null, + ); + } + + public function getResultType(): ObjectValue + { + return new ObjectValue(Message::class); + } +} diff --git a/src/TelegramBotApi.php b/src/TelegramBotApi.php index f3371ad0..a1a16c21 100644 --- a/src/TelegramBotApi.php +++ b/src/TelegramBotApi.php @@ -104,6 +104,7 @@ use Phptg\BotApi\Method\SendDice; use Phptg\BotApi\Method\SendDocument; use Phptg\BotApi\Method\SendLocation; +use Phptg\BotApi\Method\SendLivePhoto; use Phptg\BotApi\Method\SendMediaGroup; use Phptg\BotApi\Method\SendMessage; use Phptg\BotApi\Method\SendMessageDraft; @@ -2381,6 +2382,55 @@ public function sendMediaGroup( ); } + /** + * @param MessageEntity[]|null $captionEntities + * + * @see https://core.telegram.org/bots/api#sendlivephoto + */ + public function sendLivePhoto( + int|string $chatId, + string|InputFile $livePhoto, + string|InputFile $photo, + ?string $businessConnectionId = null, + ?int $messageThreadId = null, + ?int $directMessagesTopicId = null, + ?string $caption = null, + ?string $parseMode = null, + ?array $captionEntities = null, + ?bool $showCaptionAboveMedia = null, + ?bool $hasSpoiler = null, + ?bool $disableNotification = null, + ?bool $protectContent = null, + ?bool $allowPaidBroadcast = null, + ?string $messageEffectId = null, + ?SuggestedPostParameters $suggestedPostParameters = null, + ?ReplyParameters $replyParameters = null, + InlineKeyboardMarkup|ReplyKeyboardMarkup|ReplyKeyboardRemove|ForceReply|null $replyMarkup = null, + ): FailResult|Message { + return $this->call( + new SendLivePhoto( + $chatId, + $livePhoto, + $photo, + $businessConnectionId, + $messageThreadId, + $directMessagesTopicId, + $caption, + $parseMode, + $captionEntities, + $showCaptionAboveMedia, + $hasSpoiler, + $disableNotification, + $protectContent, + $allowPaidBroadcast, + $messageEffectId, + $suggestedPostParameters, + $replyParameters, + $replyMarkup, + ), + ); + } + /** * @param MessageEntity[]|null $entities * diff --git a/tests/Method/SendLivePhotoTest.php b/tests/Method/SendLivePhotoTest.php new file mode 100644 index 00000000..46c31fd3 --- /dev/null +++ b/tests/Method/SendLivePhotoTest.php @@ -0,0 +1,120 @@ +getHttpMethod()); + assertSame('sendLivePhoto', $method->getApiMethod()); + assertSame( + [ + 'chat_id' => 12, + 'live_photo' => 'fid1', + 'photo' => 'fid2', + ], + $method->getData(), + ); + } + + public function testFull(): void + { + $livePhotoFile = new InputFile(null, 'video.mp4'); + $photoFile = new InputFile(null, 'photo.jpg'); + $entity = new MessageEntity('bold', 0, 5); + $replyParameters = new ReplyParameters(23); + $replyMarkup = new ForceReply(); + $method = new SendLivePhoto( + 12, + $livePhotoFile, + $photoFile, + 'bcid1', + 99, + 123, + 'Caption', + 'HTML', + [$entity], + false, + true, + false, + false, + true, + 'meID', + new SuggestedPostParameters( + new SuggestedPostPrice('USD', 10), + ), + $replyParameters, + $replyMarkup, + ); + + assertSame( + [ + 'business_connection_id' => 'bcid1', + 'chat_id' => 12, + 'message_thread_id' => 99, + 'direct_messages_topic_id' => 123, + 'live_photo' => 'attach://file0', + 'photo' => 'attach://file1', + 'caption' => 'Caption', + 'parse_mode' => 'HTML', + 'caption_entities' => [$entity->toRequestArray()], + 'show_caption_above_media' => false, + 'has_spoiler' => true, + 'disable_notification' => false, + 'protect_content' => false, + 'allow_paid_broadcast' => true, + 'message_effect_id' => 'meID', + 'suggested_post_parameters' => (new SuggestedPostParameters( + new SuggestedPostPrice('USD', 10), + ))->toRequestArray(), + 'reply_parameters' => $replyParameters->toRequestArray(), + 'reply_markup' => $replyMarkup->toRequestArray(), + 'file0' => $livePhotoFile, + 'file1' => $photoFile, + ], + $method->getData(), + ); + } + + public function testPrepareResult(): void + { + $method = new SendLivePhoto( + 12, + 'fid1', + 'fid2', + ); + + $preparedResult = TestHelper::createSuccessStubApi([ + 'message_id' => 7, + 'date' => 1620000000, + 'chat' => [ + 'id' => 1, + 'type' => 'private', + ], + ])->call($method); + + assertSame(7, $preparedResult->messageId); + } +} diff --git a/tests/TelegramBotApi/TelegramBotApiTest.php b/tests/TelegramBotApi/TelegramBotApiTest.php index b96f1be2..bd8686cb 100644 --- a/tests/TelegramBotApi/TelegramBotApiTest.php +++ b/tests/TelegramBotApi/TelegramBotApiTest.php @@ -2083,6 +2083,23 @@ public function testSendLocation(): void assertSame(7, $result->messageId); } + public function testSendLivePhoto(): void + { + $api = TestHelper::createSuccessStubApi([ + 'message_id' => 7, + 'date' => 1620000000, + 'chat' => [ + 'id' => 1, + 'type' => 'private', + ], + ]); + + $result = $api->sendLivePhoto(12, 'fid1', 'fid2'); + + assertInstanceOf(Message::class, $result); + assertSame(7, $result->messageId); + } + public function testSendMediaGroup(): void { $api = TestHelper::createSuccessStubApi([ From 49f8451103a0ed8c5cef47e4def0971d98534280 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 13:46:12 +0300 Subject: [PATCH 22/32] Add `PaidMediaLivePhoto` type --- CHANGELOG.md | 1 + src/Type/PaidMediaLivePhoto.php | 22 +++++++++++++ tests/Type/PaidMediaLivePhotoTest.php | 47 +++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 src/Type/PaidMediaLivePhoto.php create mode 100644 tests/Type/PaidMediaLivePhotoTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index c6ec2c79..f35e325f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - New #199: Add `InputPollMedia` and `InputPollOptionMedia` types. - New #199: Add `live_photo` field to `Message` and `ExternalReplyInfo` types. - New #199: Add `SendLivePhoto` method. +- New #199: Add `PaidMediaLivePhoto` type. - New #199: Add `explanationMedia`, `media`, `membersOnly` and `countryCodes` parameters to `SendPoll` method. - New #199: Add `media` field to `InputPollOption` type. diff --git a/src/Type/PaidMediaLivePhoto.php b/src/Type/PaidMediaLivePhoto.php new file mode 100644 index 00000000..cc16e5c8 --- /dev/null +++ b/src/Type/PaidMediaLivePhoto.php @@ -0,0 +1,22 @@ +getType()); + assertSame($livePhoto, $type->livePhoto); + } + + public function testFromTelegramResult(): void + { + $type = (new ObjectFactory())->create([ + 'type' => 'live_photo', + 'live_photo' => [ + 'file_id' => 'fileId', + 'file_unique_id' => 'fileUniqueId', + 'width' => 640, + 'height' => 480, + 'duration' => 3, + ], + ], null, PaidMediaLivePhoto::class); + + assertSame('live_photo', $type->getType()); + assertInstanceOf(LivePhoto::class, $type->livePhoto); + assertSame('fileId', $type->livePhoto->fileId); + assertSame('fileUniqueId', $type->livePhoto->fileUniqueId); + assertSame(640, $type->livePhoto->width); + assertSame(480, $type->livePhoto->height); + assertSame(3, $type->livePhoto->duration); + } +} From b9967ffb895c8c36eef36ea8e375e574fcfee643 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 13:51:21 +0300 Subject: [PATCH 23/32] Add `InputPaidMediaLivePhoto` type --- AGENTS.md | 5 ++ CHANGELOG.md | 1 + src/Type/InputPaidMediaLivePhoto.php | 46 +++++++++++++ tests/Type/InputPaidMediaLivePhotoTest.php | 75 ++++++++++++++++++++++ 4 files changed, 127 insertions(+) create mode 100644 AGENTS.md create mode 100644 src/Type/InputPaidMediaLivePhoto.php create mode 100644 tests/Type/InputPaidMediaLivePhotoTest.php diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..167d8d2f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,5 @@ +# Agent Guidelines + +## Writing Tests + +- For `InputFile|string` parameters, the string must be a file ID, not a URL. diff --git a/CHANGELOG.md b/CHANGELOG.md index f35e325f..fa507467 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - New #199: Add `live_photo` field to `Message` and `ExternalReplyInfo` types. - New #199: Add `SendLivePhoto` method. - New #199: Add `PaidMediaLivePhoto` type. +- New #199: Add `InputPaidMediaLivePhoto` type. - New #199: Add `explanationMedia`, `media`, `membersOnly` and `countryCodes` parameters to `SendPoll` method. - New #199: Add `media` field to `InputPollOption` type. diff --git a/src/Type/InputPaidMediaLivePhoto.php b/src/Type/InputPaidMediaLivePhoto.php new file mode 100644 index 00000000..4cd69e8d --- /dev/null +++ b/src/Type/InputPaidMediaLivePhoto.php @@ -0,0 +1,46 @@ +media instanceof InputFile + ? 'attach://' . $fileCollector->add($this->media) + : $this->media; + $photo = $this->photo instanceof InputFile + ? 'attach://' . $fileCollector->add($this->photo) + : $this->photo; + } else { + $media = $this->media; + $photo = $this->photo; + } + + return [ + 'type' => $this->getType(), + 'media' => $media, + 'photo' => $photo, + ]; + } +} diff --git a/tests/Type/InputPaidMediaLivePhotoTest.php b/tests/Type/InputPaidMediaLivePhotoTest.php new file mode 100644 index 00000000..0e6163f9 --- /dev/null +++ b/tests/Type/InputPaidMediaLivePhotoTest.php @@ -0,0 +1,75 @@ +getType()); + assertSame( + [ + 'type' => 'live_photo', + 'media' => 'file_id_video', + 'photo' => 'file_id_photo', + ], + $inputMedia->toRequestArray(), + ); + + $fileCollector = new FileCollector(); + assertSame( + [ + 'type' => 'live_photo', + 'media' => 'file_id_video', + 'photo' => 'file_id_photo', + ], + $inputMedia->toRequestArray($fileCollector), + ); + assertSame([], $fileCollector->get()); + } + + public function testFull(): void + { + $mediaFile = new InputFile(null); + $photoFile = new InputFile(null); + $inputMedia = new InputPaidMediaLivePhoto($mediaFile, $photoFile); + + assertSame('live_photo', $inputMedia->getType()); + assertSame( + [ + 'type' => 'live_photo', + 'media' => $mediaFile, + 'photo' => $photoFile, + ], + $inputMedia->toRequestArray(), + ); + + $fileCollector = new FileCollector(); + assertSame( + [ + 'type' => 'live_photo', + 'media' => 'attach://file0', + 'photo' => 'attach://file1', + ], + $inputMedia->toRequestArray($fileCollector), + ); + assertSame( + [ + 'file0' => $mediaFile, + 'file1' => $photoFile, + ], + $fileCollector->get(), + ); + } +} From dea88099f09e4cf923fc6f3137455a46807f0aef Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 13:57:58 +0300 Subject: [PATCH 24/32] `SendMediaGroup` method now supports `InputMediaLivePhoto` type --- CHANGELOG.md | 1 + src/Method/SendMediaGroup.php | 5 +++-- src/TelegramBotApi.php | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa507467..1105f8de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - New #199: Add `InputPaidMediaLivePhoto` type. - New #199: Add `explanationMedia`, `media`, `membersOnly` and `countryCodes` parameters to `SendPoll` method. - New #199: Add `media` field to `InputPollOption` type. +- Enh #199: `SendMediaGroup` method now supports `InputMediaLivePhoto` type. ## 0.20 April 26, 2026 diff --git a/src/Method/SendMediaGroup.php b/src/Method/SendMediaGroup.php index e8569ce1..e9b03dda 100644 --- a/src/Method/SendMediaGroup.php +++ b/src/Method/SendMediaGroup.php @@ -10,6 +10,7 @@ use Phptg\BotApi\MethodInterface; use Phptg\BotApi\Type\InputMediaAudio; use Phptg\BotApi\Type\InputMediaDocument; +use Phptg\BotApi\Type\InputMediaLivePhoto; use Phptg\BotApi\Type\InputMediaPhoto; use Phptg\BotApi\Type\InputMediaVideo; use Phptg\BotApi\Type\Message; @@ -23,7 +24,7 @@ final readonly class SendMediaGroup implements MethodInterface { /** - * @param InputMediaAudio[]|InputMediaDocument[]|InputMediaPhoto[]|InputMediaVideo[] $media + * @param InputMediaAudio[]|InputMediaDocument[]|InputMediaLivePhoto[]|InputMediaPhoto[]|InputMediaVideo[] $media */ public function __construct( private int|string $chatId, @@ -53,7 +54,7 @@ public function getData(): array $fileCollector = new FileCollector(); $media = array_map( static function ( - InputMediaAudio|InputMediaDocument|InputMediaPhoto|InputMediaVideo $inputMedia, + InputMediaAudio|InputMediaDocument|InputMediaLivePhoto|InputMediaPhoto|InputMediaVideo $inputMedia, ) use ($fileCollector): array { return $inputMedia->toRequestArray($fileCollector); }, diff --git a/src/TelegramBotApi.php b/src/TelegramBotApi.php index a1a16c21..706fab42 100644 --- a/src/TelegramBotApi.php +++ b/src/TelegramBotApi.php @@ -214,6 +214,7 @@ use Phptg\BotApi\Type\InputMedia; use Phptg\BotApi\Type\InputMediaAudio; use Phptg\BotApi\Type\InputMediaDocument; +use Phptg\BotApi\Type\InputMediaLivePhoto; use Phptg\BotApi\Type\InputMediaPhoto; use Phptg\BotApi\Type\InputMediaVideo; use Phptg\BotApi\Type\InputPaidMedia; @@ -2351,7 +2352,7 @@ public function sendLocation( /** * @see https://core.telegram.org/bots/api#sendmediagroup * - * @param InputMediaAudio[]|InputMediaDocument[]|InputMediaPhoto[]|InputMediaVideo[] $media + * @param InputMediaAudio[]|InputMediaDocument[]|InputMediaLivePhoto[]|InputMediaPhoto[]|InputMediaVideo[] $media * @return FailResult|Message[] */ public function sendMediaGroup( From 68f7cb9af94384447aee2c033c89dd15001de29e Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 14:05:17 +0300 Subject: [PATCH 25/32] Add `BotAccessSettings` type --- CHANGELOG.md | 1 + src/Type/BotAccessSettings.php | 24 ++++++++++++ tests/Type/BotAccessSettingsTest.php | 55 ++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 src/Type/BotAccessSettings.php create mode 100644 tests/Type/BotAccessSettingsTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 1105f8de..2d60dd05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ - New #199: Add `explanationMedia`, `media`, `membersOnly` and `countryCodes` parameters to `SendPoll` method. - New #199: Add `media` field to `InputPollOption` type. - Enh #199: `SendMediaGroup` method now supports `InputMediaLivePhoto` type. +- New #199: Add `BotAccessSettings` type. ## 0.20 April 26, 2026 diff --git a/src/Type/BotAccessSettings.php b/src/Type/BotAccessSettings.php new file mode 100644 index 00000000..cea37c31 --- /dev/null +++ b/src/Type/BotAccessSettings.php @@ -0,0 +1,24 @@ +isAccessRestricted); + assertNull($settings->addedUsers); + } + + public function testFull(): void + { + $user1 = new User(1, false, 'Alice'); + $user2 = new User(2, false, 'Bob'); + $settings = new BotAccessSettings(true, [$user1, $user2]); + + assertSame(true, $settings->isAccessRestricted); + assertSame([$user1, $user2], $settings->addedUsers); + } + + public function testFromTelegramResult(): void + { + $settings = (new ObjectFactory())->create([ + 'is_access_restricted' => true, + 'added_users' => [ + ['id' => 1, 'is_bot' => false, 'first_name' => 'Alice'], + ['id' => 2, 'is_bot' => false, 'first_name' => 'Bob'], + ], + ], null, BotAccessSettings::class); + + assertInstanceOf(BotAccessSettings::class, $settings); + assertSame(true, $settings->isAccessRestricted); + assertInstanceOf(User::class, $settings->addedUsers[0]); + assertSame(1, $settings->addedUsers[0]->id); + assertSame('Alice', $settings->addedUsers[0]->firstName); + assertInstanceOf(User::class, $settings->addedUsers[1]); + assertSame(2, $settings->addedUsers[1]->id); + assertSame('Bob', $settings->addedUsers[1]->firstName); + } +} From 4edb58a9e66f95f6638831dc44613ba4f7b3b184 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 14:10:08 +0300 Subject: [PATCH 26/32] Add `GetManagedBotAccessSettings` method --- CHANGELOG.md | 1 + src/Method/GetManagedBotAccessSettings.php | 42 ++++++++++++++++ src/TelegramBotApi.php | 10 ++++ .../GetManagedBotAccessSettingsTest.php | 48 +++++++++++++++++++ tests/TelegramBotApi/TelegramBotApiTest.php | 18 +++++++ 5 files changed, 119 insertions(+) create mode 100644 src/Method/GetManagedBotAccessSettings.php create mode 100644 tests/Method/GetManagedBotAccessSettingsTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d60dd05..202036ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - New #199: Add `media` field to `InputPollOption` type. - Enh #199: `SendMediaGroup` method now supports `InputMediaLivePhoto` type. - New #199: Add `BotAccessSettings` type. +- New #199: Add `GetManagedBotAccessSettings` method. ## 0.20 April 26, 2026 diff --git a/src/Method/GetManagedBotAccessSettings.php b/src/Method/GetManagedBotAccessSettings.php new file mode 100644 index 00000000..a886ec52 --- /dev/null +++ b/src/Method/GetManagedBotAccessSettings.php @@ -0,0 +1,42 @@ + + */ +final readonly class GetManagedBotAccessSettings implements MethodInterface +{ + public function __construct( + private int $userId, + ) {} + + public function getHttpMethod(): HttpMethod + { + return HttpMethod::POST; + } + + public function getApiMethod(): string + { + return 'getManagedBotAccessSettings'; + } + + public function getData(): array + { + return ['user_id' => $this->userId]; + } + + public function getResultType(): ObjectValue + { + return new ObjectValue(BotAccessSettings::class); + } +} diff --git a/src/TelegramBotApi.php b/src/TelegramBotApi.php index 706fab42..f30d4621 100644 --- a/src/TelegramBotApi.php +++ b/src/TelegramBotApi.php @@ -54,6 +54,7 @@ use Phptg\BotApi\Method\GetChatMenuButton; use Phptg\BotApi\Method\GetFile; use Phptg\BotApi\Method\GetForumTopicIconStickers; +use Phptg\BotApi\Method\GetManagedBotAccessSettings; use Phptg\BotApi\Method\GetManagedBotToken; use Phptg\BotApi\Method\GetMe; use Phptg\BotApi\Method\GetMyCommands; @@ -187,6 +188,7 @@ use Phptg\BotApi\Transport\NativeTransport; use Phptg\BotApi\Transport\TransportInterface; use Phptg\BotApi\Type\AcceptedGiftTypes; +use Phptg\BotApi\Type\BotAccessSettings; use Phptg\BotApi\Type\BotCommand; use Phptg\BotApi\Type\BotCommandScope; use Phptg\BotApi\Type\BotDescription; @@ -1407,6 +1409,14 @@ public function getManagedBotToken(int $userId): FailResult|string return $this->call(new GetManagedBotToken($userId)); } + /** + * @see https://core.telegram.org/bots/api#getmanagedbotaccesssettings + */ + public function getManagedBotAccessSettings(int $userId): FailResult|BotAccessSettings + { + return $this->call(new GetManagedBotAccessSettings($userId)); + } + /** * @see https://core.telegram.org/bots/api#getmycommands */ diff --git a/tests/Method/GetManagedBotAccessSettingsTest.php b/tests/Method/GetManagedBotAccessSettingsTest.php new file mode 100644 index 00000000..c8065ba0 --- /dev/null +++ b/tests/Method/GetManagedBotAccessSettingsTest.php @@ -0,0 +1,48 @@ +getHttpMethod()); + assertSame('getManagedBotAccessSettings', $method->getApiMethod()); + assertSame( + [ + 'user_id' => 123, + ], + $method->getData(), + ); + } + + public function testPrepareResult(): void + { + $method = new GetManagedBotAccessSettings(123); + + $preparedResult = TestHelper::createSuccessStubApi([ + 'is_access_restricted' => true, + 'added_users' => [ + ['id' => 1, 'is_bot' => false, 'first_name' => 'Alice'], + ], + ])->call($method); + + assertInstanceOf(BotAccessSettings::class, $preparedResult); + assertSame(true, $preparedResult->isAccessRestricted); + assertSame(1, $preparedResult->addedUsers[0]->id); + assertSame('Alice', $preparedResult->addedUsers[0]->firstName); + } +} diff --git a/tests/TelegramBotApi/TelegramBotApiTest.php b/tests/TelegramBotApi/TelegramBotApiTest.php index bd8686cb..3bca9aa8 100644 --- a/tests/TelegramBotApi/TelegramBotApiTest.php +++ b/tests/TelegramBotApi/TelegramBotApiTest.php @@ -14,6 +14,7 @@ use Phptg\BotApi\Tests\Support\TransportMock; use Phptg\BotApi\Transport\ApiResponse; use Phptg\BotApi\Type\AcceptedGiftTypes; +use Phptg\BotApi\Type\BotAccessSettings; use Phptg\BotApi\Type\BotCommand; use Phptg\BotApi\Type\BotDescription; use Phptg\BotApi\Type\BotName; @@ -1299,6 +1300,23 @@ public function testGetManagedBotToken(): void assertSame('123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11', $result); } + public function testGetManagedBotAccessSettings(): void + { + $api = TestHelper::createSuccessStubApi([ + 'is_access_restricted' => true, + 'added_users' => [ + ['id' => 1, 'is_bot' => false, 'first_name' => 'Alice'], + ], + ]); + + $result = $api->getManagedBotAccessSettings(789); + + assertInstanceOf(BotAccessSettings::class, $result); + assertSame(true, $result->isAccessRestricted); + assertSame(1, $result->addedUsers[0]->id); + assertSame('Alice', $result->addedUsers[0]->firstName); + } + public function testGetMyCommands(): void { $api = TestHelper::createSuccessStubApi([ From 5b4094d130ae6fdbd8c4b056b3433626ff1517ef Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 14:16:35 +0300 Subject: [PATCH 27/32] Add `SetManagedBotAccessSettings` method --- CHANGELOG.md | 1 + src/Method/SetManagedBotAccessSettings.php | 53 ++++++++++++++++++ src/TelegramBotApi.php | 13 +++++ .../SetManagedBotAccessSettingsTest.php | 54 +++++++++++++++++++ tests/TelegramBotApi/TelegramBotApiTest.php | 9 ++++ 5 files changed, 130 insertions(+) create mode 100644 src/Method/SetManagedBotAccessSettings.php create mode 100644 tests/Method/SetManagedBotAccessSettingsTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 202036ef..b2499c1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - Enh #199: `SendMediaGroup` method now supports `InputMediaLivePhoto` type. - New #199: Add `BotAccessSettings` type. - New #199: Add `GetManagedBotAccessSettings` method. +- New #199: Add `SetManagedBotAccessSettings` method. ## 0.20 April 26, 2026 diff --git a/src/Method/SetManagedBotAccessSettings.php b/src/Method/SetManagedBotAccessSettings.php new file mode 100644 index 00000000..e2c4377a --- /dev/null +++ b/src/Method/SetManagedBotAccessSettings.php @@ -0,0 +1,53 @@ + + */ +final readonly class SetManagedBotAccessSettings implements MethodInterface +{ + /** + * @param int[]|null $addedUserIds + */ + public function __construct( + private int $userId, + private bool $isAccessRestricted, + private ?array $addedUserIds = null, + ) {} + + public function getHttpMethod(): HttpMethod + { + return HttpMethod::POST; + } + + public function getApiMethod(): string + { + return 'setManagedBotAccessSettings'; + } + + public function getData(): array + { + return array_filter( + [ + 'user_id' => $this->userId, + 'is_access_restricted' => $this->isAccessRestricted, + 'added_user_ids' => $this->addedUserIds, + ], + static fn(mixed $value): bool => $value !== null, + ); + } + + public function getResultType(): TrueValue + { + return new TrueValue(); + } +} diff --git a/src/TelegramBotApi.php b/src/TelegramBotApi.php index f30d4621..85d10b8d 100644 --- a/src/TelegramBotApi.php +++ b/src/TelegramBotApi.php @@ -129,6 +129,7 @@ use Phptg\BotApi\Method\SetChatPhoto; use Phptg\BotApi\Method\SetChatStickerSet; use Phptg\BotApi\Method\SetChatTitle; +use Phptg\BotApi\Method\SetManagedBotAccessSettings; use Phptg\BotApi\Method\SetMessageReaction; use Phptg\BotApi\Method\SetMyCommands; use Phptg\BotApi\Method\SetMyDefaultAdministratorRights; @@ -3074,6 +3075,18 @@ public function setChatTitle(int|string $chatId, string $title): FailResult|true ); } + /** + * @see https://core.telegram.org/bots/api#setmanagedbotaccesssettings + * + * @param int[]|null $addedUserIds + */ + public function setManagedBotAccessSettings(int $userId, bool $isAccessRestricted, ?array $addedUserIds = null): FailResult|true + { + return $this->call( + new SetManagedBotAccessSettings($userId, $isAccessRestricted, $addedUserIds), + ); + } + /** * @see https://core.telegram.org/bots/api#setcustomemojistickersetthumbnail */ diff --git a/tests/Method/SetManagedBotAccessSettingsTest.php b/tests/Method/SetManagedBotAccessSettingsTest.php new file mode 100644 index 00000000..1a4f53a5 --- /dev/null +++ b/tests/Method/SetManagedBotAccessSettingsTest.php @@ -0,0 +1,54 @@ +getHttpMethod()); + assertSame('setManagedBotAccessSettings', $method->getApiMethod()); + assertSame( + [ + 'user_id' => 123, + 'is_access_restricted' => true, + ], + $method->getData(), + ); + } + + public function testFull(): void + { + $method = new SetManagedBotAccessSettings(123, true, [456, 789]); + + assertSame( + [ + 'user_id' => 123, + 'is_access_restricted' => true, + 'added_user_ids' => [456, 789], + ], + $method->getData(), + ); + } + + public function testPrepareResult(): void + { + $method = new SetManagedBotAccessSettings(123, true); + + $preparedResult = TestHelper::createSuccessStubApi(true)->call($method); + + assertTrue($preparedResult); + } +} diff --git a/tests/TelegramBotApi/TelegramBotApiTest.php b/tests/TelegramBotApi/TelegramBotApiTest.php index 3bca9aa8..db2b7941 100644 --- a/tests/TelegramBotApi/TelegramBotApiTest.php +++ b/tests/TelegramBotApi/TelegramBotApiTest.php @@ -2374,6 +2374,15 @@ public function testSetChatTitle(): void assertTrue($result); } + public function testSetManagedBotAccessSettings(): void + { + $api = TestHelper::createSuccessStubApi(true); + + $result = $api->setManagedBotAccessSettings(789, true, [1, 2]); + + assertTrue($result); + } + public function testSetCustomEmojiStickerSetThumbnail(): void { $api = TestHelper::createSuccessStubApi(true); From a2d582e71ef4b8f66394aa22964acc01ba363162 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 14:21:11 +0300 Subject: [PATCH 28/32] Add `GetUserPersonalChatMessages` method --- CHANGELOG.md | 1 + src/Method/GetUserPersonalChatMessages.php | 46 +++++++++++++ src/TelegramBotApi.php | 11 ++++ .../GetUserPersonalChatMessagesTest.php | 65 +++++++++++++++++++ tests/TelegramBotApi/TelegramBotApiTest.php | 20 ++++++ 5 files changed, 143 insertions(+) create mode 100644 src/Method/GetUserPersonalChatMessages.php create mode 100644 tests/Method/GetUserPersonalChatMessagesTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index b2499c1e..ff4fd414 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ - New #199: Add `BotAccessSettings` type. - New #199: Add `GetManagedBotAccessSettings` method. - New #199: Add `SetManagedBotAccessSettings` method. +- New #199: Add `GetUserPersonalChatMessages` method. ## 0.20 April 26, 2026 diff --git a/src/Method/GetUserPersonalChatMessages.php b/src/Method/GetUserPersonalChatMessages.php new file mode 100644 index 00000000..71272baa --- /dev/null +++ b/src/Method/GetUserPersonalChatMessages.php @@ -0,0 +1,46 @@ +> + */ +final readonly class GetUserPersonalChatMessages implements MethodInterface +{ + public function __construct( + private int $userId, + private int $limit, + ) {} + + public function getHttpMethod(): HttpMethod + { + return HttpMethod::POST; + } + + public function getApiMethod(): string + { + return 'getUserPersonalChatMessages'; + } + + public function getData(): array + { + return [ + 'user_id' => $this->userId, + 'limit' => $this->limit, + ]; + } + + public function getResultType(): ArrayOfObjectsValue + { + return new ArrayOfObjectsValue(Message::class); + } +} diff --git a/src/TelegramBotApi.php b/src/TelegramBotApi.php index 85d10b8d..1acfe6c6 100644 --- a/src/TelegramBotApi.php +++ b/src/TelegramBotApi.php @@ -65,6 +65,7 @@ use Phptg\BotApi\Method\GetMyStarBalance; use Phptg\BotApi\Method\GetUserChatBoosts; use Phptg\BotApi\Method\GetUserGifts; +use Phptg\BotApi\Method\GetUserPersonalChatMessages; use Phptg\BotApi\Method\GetUserProfileAudios; use Phptg\BotApi\Method\GetUserProfilePhotos; use Phptg\BotApi\Method\GiftPremiumSubscription; @@ -1540,6 +1541,16 @@ public function getUserGifts( ); } + /** + * @see https://core.telegram.org/bots/api#getuserpersonalchatmessages + */ + public function getUserPersonalChatMessages(int $userId, int $limit): FailResult|array + { + return $this->call( + new GetUserPersonalChatMessages($userId, $limit), + ); + } + /** * @see https://core.telegram.org/bots/api#getuserprofileaudios */ diff --git a/tests/Method/GetUserPersonalChatMessagesTest.php b/tests/Method/GetUserPersonalChatMessagesTest.php new file mode 100644 index 00000000..e6867dc1 --- /dev/null +++ b/tests/Method/GetUserPersonalChatMessagesTest.php @@ -0,0 +1,65 @@ +getHttpMethod()); + assertSame('getUserPersonalChatMessages', $method->getApiMethod()); + assertSame( + [ + 'user_id' => 123, + 'limit' => 10, + ], + $method->getData(), + ); + } + + public function testPrepareResult(): void + { + $method = new GetUserPersonalChatMessages(123, 10); + + $result = TestHelper::createSuccessStubApi([ + [ + 'message_id' => 1, + 'date' => 1620000000, + 'chat' => [ + 'id' => 1, + 'type' => 'private', + ], + ], + [ + 'message_id' => 2, + 'date' => 1620000001, + 'chat' => [ + 'id' => 1, + 'type' => 'private', + ], + ], + ])->call($method); + + assertIsArray($result); + assertCount(2, $result); + assertInstanceOf(Message::class, $result[0]); + assertSame(1, $result[0]->messageId); + assertInstanceOf(Message::class, $result[1]); + assertSame(2, $result[1]->messageId); + } +} diff --git a/tests/TelegramBotApi/TelegramBotApiTest.php b/tests/TelegramBotApi/TelegramBotApiTest.php index db2b7941..92236746 100644 --- a/tests/TelegramBotApi/TelegramBotApiTest.php +++ b/tests/TelegramBotApi/TelegramBotApiTest.php @@ -1576,6 +1576,26 @@ public function testGetUserGifts(): void assertInstanceOf(OwnedGifts::class, $result); } + public function testGetUserPersonalChatMessages(): void + { + $api = TestHelper::createSuccessStubApi([ + [ + 'message_id' => 1, + 'date' => 1620000000, + 'chat' => [ + 'id' => 1, + 'type' => 'private', + ], + ], + ]); + + $result = $api->getUserPersonalChatMessages(123, 10); + + assertIsArray($result); + assertCount(1, $result); + assertInstanceOf(Message::class, $result[0]); + } + public function testGetUserProfileAudios(): void { $api = TestHelper::createSuccessStubApi([ From 6d2cf40f3b228d34ac749fbf025872faf07830b2 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 14:33:16 +0300 Subject: [PATCH 29/32] fix --- src/Type/LivePhoto.php | 2 +- tests/Type/LivePhotoTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Type/LivePhoto.php b/src/Type/LivePhoto.php index 2781ed96..b867ff5e 100644 --- a/src/Type/LivePhoto.php +++ b/src/Type/LivePhoto.php @@ -25,6 +25,6 @@ public function __construct( #[ArrayOfObjectsValue(PhotoSize::class)] public ?array $photo = null, public ?string $mimeType = null, - public ?string $fileSize = null, + public ?int $fileSize = null, ) {} } diff --git a/tests/Type/LivePhotoTest.php b/tests/Type/LivePhotoTest.php index f911909b..634183ab 100644 --- a/tests/Type/LivePhotoTest.php +++ b/tests/Type/LivePhotoTest.php @@ -57,7 +57,7 @@ public function testFromTelegramResult(): void ], ], 'mime_type' => 'video/mp4', - 'file_size' => '2097152', + 'file_size' => 2097152, ], null, LivePhoto::class); assertSame('file_id_abc', $livePhoto->fileId); @@ -69,6 +69,6 @@ public function testFromTelegramResult(): void assertSame('photo_file_id_1', $livePhoto->photo[0]->fileId); assertSame('photo_file_id_2', $livePhoto->photo[1]->fileId); assertSame('video/mp4', $livePhoto->mimeType); - assertSame('2097152', $livePhoto->fileSize); + assertSame(2097152, $livePhoto->fileSize); } } From 1ec30904fea27d75d594ace9d2de1c2c7ea233e7 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 14:35:25 +0300 Subject: [PATCH 30/32] fix --- src/Method/GetManagedBotAccessSettings.php | 2 +- src/Method/GetUserPersonalChatMessages.php | 2 +- tests/Method/GetManagedBotAccessSettingsTest.php | 2 +- tests/Method/GetUserPersonalChatMessagesTest.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Method/GetManagedBotAccessSettings.php b/src/Method/GetManagedBotAccessSettings.php index a886ec52..25b51256 100644 --- a/src/Method/GetManagedBotAccessSettings.php +++ b/src/Method/GetManagedBotAccessSettings.php @@ -22,7 +22,7 @@ public function __construct( public function getHttpMethod(): HttpMethod { - return HttpMethod::POST; + return HttpMethod::GET; } public function getApiMethod(): string diff --git a/src/Method/GetUserPersonalChatMessages.php b/src/Method/GetUserPersonalChatMessages.php index 71272baa..52f6d7bd 100644 --- a/src/Method/GetUserPersonalChatMessages.php +++ b/src/Method/GetUserPersonalChatMessages.php @@ -23,7 +23,7 @@ public function __construct( public function getHttpMethod(): HttpMethod { - return HttpMethod::POST; + return HttpMethod::GET; } public function getApiMethod(): string diff --git a/tests/Method/GetManagedBotAccessSettingsTest.php b/tests/Method/GetManagedBotAccessSettingsTest.php index c8065ba0..50d91f06 100644 --- a/tests/Method/GetManagedBotAccessSettingsTest.php +++ b/tests/Method/GetManagedBotAccessSettingsTest.php @@ -19,7 +19,7 @@ public function testBase(): void { $method = new GetManagedBotAccessSettings(123); - assertSame(HttpMethod::POST, $method->getHttpMethod()); + assertSame(HttpMethod::GET, $method->getHttpMethod()); assertSame('getManagedBotAccessSettings', $method->getApiMethod()); assertSame( [ diff --git a/tests/Method/GetUserPersonalChatMessagesTest.php b/tests/Method/GetUserPersonalChatMessagesTest.php index e6867dc1..ec8fe2b5 100644 --- a/tests/Method/GetUserPersonalChatMessagesTest.php +++ b/tests/Method/GetUserPersonalChatMessagesTest.php @@ -21,7 +21,7 @@ public function testBase(): void { $method = new GetUserPersonalChatMessages(123, 10); - assertSame(HttpMethod::POST, $method->getHttpMethod()); + assertSame(HttpMethod::GET, $method->getHttpMethod()); assertSame('getUserPersonalChatMessages', $method->getApiMethod()); assertSame( [ From 7cad54beb853eaf34629e51166f22805a4c76036 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 14:47:03 +0300 Subject: [PATCH 31/32] `text` parameter in `SendMessageDraft` method is now optional --- CHANGELOG.md | 1 + src/Method/SendMessageDraft.php | 2 +- src/TelegramBotApi.php | 2 +- tests/Method/SendMessageDraftTest.php | 3 +-- tests/TelegramBotApi/TelegramBotApiTest.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff4fd414..819a78f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - New #199: Add `GetManagedBotAccessSettings` method. - New #199: Add `SetManagedBotAccessSettings` method. - New #199: Add `GetUserPersonalChatMessages` method. +- Chg #199: `text` parameter in `SendMessageDraft` method is now optional. ## 0.20 April 26, 2026 diff --git a/src/Method/SendMessageDraft.php b/src/Method/SendMessageDraft.php index 45401615..872f1f64 100644 --- a/src/Method/SendMessageDraft.php +++ b/src/Method/SendMessageDraft.php @@ -22,7 +22,7 @@ public function __construct( private int $chatId, private int $draftId, - private string $text, + private ?string $text = null, private ?int $messageThreadId = null, private ?string $parseMode = null, private ?array $entities = null, diff --git a/src/TelegramBotApi.php b/src/TelegramBotApi.php index 1acfe6c6..632be497 100644 --- a/src/TelegramBotApi.php +++ b/src/TelegramBotApi.php @@ -2505,7 +2505,7 @@ public function sendMessage( public function sendMessageDraft( int $chatId, int $draftId, - string $text, + ?string $text = null, ?int $messageThreadId = null, ?string $parseMode = null, ?array $entities = null, diff --git a/tests/Method/SendMessageDraftTest.php b/tests/Method/SendMessageDraftTest.php index f3222ddd..88c345ef 100644 --- a/tests/Method/SendMessageDraftTest.php +++ b/tests/Method/SendMessageDraftTest.php @@ -17,7 +17,7 @@ final class SendMessageDraftTest extends TestCase { public function testBase(): void { - $method = new SendMessageDraft(12, 100, 'hello'); + $method = new SendMessageDraft(12, 100); assertSame(HttpMethod::POST, $method->getHttpMethod()); assertSame('sendMessageDraft', $method->getApiMethod()); @@ -25,7 +25,6 @@ public function testBase(): void [ 'chat_id' => 12, 'draft_id' => 100, - 'text' => 'hello', ], $method->getData(), ); diff --git a/tests/TelegramBotApi/TelegramBotApiTest.php b/tests/TelegramBotApi/TelegramBotApiTest.php index 92236746..00ef28c7 100644 --- a/tests/TelegramBotApi/TelegramBotApiTest.php +++ b/tests/TelegramBotApi/TelegramBotApiTest.php @@ -2180,7 +2180,7 @@ public function testSendMessageDraft(): void { $api = TestHelper::createSuccessStubApi(true); - $result = $api->sendMessageDraft(12, 100, 'hello'); + $result = $api->sendMessageDraft(12, 100); assertTrue($result); } From 20761dfa9572a53da5c8ba0d0d446976d3e51020 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 9 May 2026 14:48:07 +0300 Subject: [PATCH 32/32] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 85ba2438..52ec9e79 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The package provides a simple and convenient way to interact with the Telegram Bot API. -✔️ Telegram Bot API 9.6 (April 3, 2026) is **fully supported**. +✔️ Telegram Bot API 10.0 (May 8, 2026) is **fully supported**. ♻️ **Zero dependencies** — no third-party libraries, only native PHP.