From 3c28d348a20ac19cb5794091a887d1efcd359ff6 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 3 Apr 2026 19:38:02 +0300 Subject: [PATCH 01/18] Add `canManageBots` field to `User` type. --- CHANGELOG.md | 1 + src/Type/User.php | 2 ++ tests/Type/UserTest.php | 5 +++++ 3 files changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54959b52..86e89271 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 0.17.1 under development - Enh #190: Open file in binary mode in `InputFile::fromLocalFile()` method. +- New #191: Add `canManageBots` field to `User` type. ## 0.17 March 1, 2026 diff --git a/src/Type/User.php b/src/Type/User.php index d4cdcc6b..a46ae50a 100644 --- a/src/Type/User.php +++ b/src/Type/User.php @@ -27,6 +27,7 @@ public function __construct( public ?bool $hasMainWebApp = null, public ?bool $hasTopicsEnabled = null, public ?bool $allowsUsersToCreateTopics = null, + public ?bool $canManageBots = null, ) {} public function toRequestArray(): array @@ -48,6 +49,7 @@ public function toRequestArray(): array 'has_main_web_app' => $this->hasMainWebApp, 'has_topics_enabled' => $this->hasTopicsEnabled, 'allows_users_to_create_topics' => $this->allowsUsersToCreateTopics, + 'can_manage_bots' => $this->canManageBots, ], static fn(mixed $value): bool => $value !== null, ); diff --git a/tests/Type/UserTest.php b/tests/Type/UserTest.php index 87939a05..e6e3c3c4 100644 --- a/tests/Type/UserTest.php +++ b/tests/Type/UserTest.php @@ -33,6 +33,7 @@ public function testBase(): void assertNull($user->hasMainWebApp); assertNull($user->hasTopicsEnabled); assertNull($user->allowsUsersToCreateTopics); + assertNull($user->canManageBots); } public function testToRequestArray(): void @@ -53,6 +54,7 @@ public function testToRequestArray(): void false, true, true, + true, ); assertSame( @@ -72,6 +74,7 @@ public function testToRequestArray(): void 'has_main_web_app' => false, 'has_topics_enabled' => true, 'allows_users_to_create_topics' => true, + 'can_manage_bots' => true, ], $user->toRequestArray(), ); @@ -95,6 +98,7 @@ public function testFromTelegramResult(): void 'has_main_web_app' => false, 'has_topics_enabled' => true, 'allows_users_to_create_topics' => true, + 'can_manage_bots' => true, ], null, User::class); assertInstanceOf(User::class, $user); @@ -113,5 +117,6 @@ public function testFromTelegramResult(): void assertSame(false, $user->hasMainWebApp); assertSame(true, $user->hasTopicsEnabled); assertSame(true, $user->allowsUsersToCreateTopics); + assertSame(true, $user->canManageBots); } } From f22c987fa2bdd0ffddf036dfe37e8b94d779a9f7 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 3 Apr 2026 19:45:22 +0300 Subject: [PATCH 02/18] Add `KeyboardButtonRequestManagedBot` type. Add `request_managed_bot` field to `KeyboardButton` type --- CHANGELOG.md | 2 + src/Type/KeyboardButton.php | 2 + src/Type/KeyboardButtonRequestManagedBot.php | 31 +++++++++++ .../KeyboardButtonRequestManagedBotTest.php | 52 +++++++++++++++++++ tests/Type/KeyboardButtonTest.php | 6 +++ 5 files changed, 93 insertions(+) create mode 100644 src/Type/KeyboardButtonRequestManagedBot.php create mode 100644 tests/Type/KeyboardButtonRequestManagedBotTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 86e89271..1f96d198 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ - Enh #190: Open file in binary mode in `InputFile::fromLocalFile()` method. - New #191: Add `canManageBots` field to `User` type. +- New #191: Add `KeyboardButtonRequestManagedBot` type. +- New #191: Add `request_managed_bot` field to `KeyboardButton` type. ## 0.17 March 1, 2026 diff --git a/src/Type/KeyboardButton.php b/src/Type/KeyboardButton.php index 3e4ce7a3..e15b57f5 100644 --- a/src/Type/KeyboardButton.php +++ b/src/Type/KeyboardButton.php @@ -21,6 +21,7 @@ public function __construct( public ?WebAppInfo $webApp = null, public ?string $iconCustomEmojiId = null, public ?string $style = null, + public ?KeyboardButtonRequestManagedBot $requestManagedBot = null, ) {} public function toRequestArray(): array @@ -32,6 +33,7 @@ public function toRequestArray(): array 'style' => $this->style, 'request_users' => $this->requestUsers?->toRequestArray(), 'request_chat' => $this->requestChat?->toRequestArray(), + 'request_managed_bot' => $this->requestManagedBot?->toRequestArray(), 'request_contact' => $this->requestContact, 'request_location' => $this->requestLocation, 'request_poll' => $this->requestPoll?->toRequestArray(), diff --git a/src/Type/KeyboardButtonRequestManagedBot.php b/src/Type/KeyboardButtonRequestManagedBot.php new file mode 100644 index 00000000..02a372b6 --- /dev/null +++ b/src/Type/KeyboardButtonRequestManagedBot.php @@ -0,0 +1,31 @@ + $this->requestId, + 'suggested_name' => $this->suggestedName, + 'suggested_username' => $this->suggestedUsername, + ], + static fn(mixed $value): bool => $value !== null, + ); + } +} diff --git a/tests/Type/KeyboardButtonRequestManagedBotTest.php b/tests/Type/KeyboardButtonRequestManagedBotTest.php new file mode 100644 index 00000000..a41525ce --- /dev/null +++ b/tests/Type/KeyboardButtonRequestManagedBotTest.php @@ -0,0 +1,52 @@ +requestId); + assertNull($keyboardButtonRequestManagedBot->suggestedName); + assertNull($keyboardButtonRequestManagedBot->suggestedUsername); + + assertSame( + [ + 'request_id' => 1, + ], + $keyboardButtonRequestManagedBot->toRequestArray(), + ); + } + + public function testFilled(): void + { + $keyboardButtonRequestManagedBot = new KeyboardButtonRequestManagedBot( + 1, + 'My Bot', + 'my_bot', + ); + + assertSame(1, $keyboardButtonRequestManagedBot->requestId); + assertSame('My Bot', $keyboardButtonRequestManagedBot->suggestedName); + assertSame('my_bot', $keyboardButtonRequestManagedBot->suggestedUsername); + + assertSame( + [ + 'request_id' => 1, + 'suggested_name' => 'My Bot', + 'suggested_username' => 'my_bot', + ], + $keyboardButtonRequestManagedBot->toRequestArray(), + ); + } +} diff --git a/tests/Type/KeyboardButtonTest.php b/tests/Type/KeyboardButtonTest.php index a0404803..534da793 100644 --- a/tests/Type/KeyboardButtonTest.php +++ b/tests/Type/KeyboardButtonTest.php @@ -8,6 +8,7 @@ use Phptg\BotApi\Type\KeyboardButton; use Phptg\BotApi\Type\KeyboardButtonPollType; use Phptg\BotApi\Type\KeyboardButtonRequestChat; +use Phptg\BotApi\Type\KeyboardButtonRequestManagedBot; use Phptg\BotApi\Type\KeyboardButtonRequestUsers; use Phptg\BotApi\Type\WebAppInfo; @@ -27,6 +28,7 @@ public function testBase(): void assertNull($button->style); assertNull($button->requestUsers); assertNull($button->requestChat); + assertNull($button->requestManagedBot); assertNull($button->requestContact); assertNull($button->requestLocation); assertNull($button->requestPoll); @@ -44,6 +46,7 @@ public function testFilled(): void { $requestUsers = new KeyboardButtonRequestUsers(1); $requestChat = new KeyboardButtonRequestChat(2, true); + $requestManagedBot = new KeyboardButtonRequestManagedBot(3); $requestPoll = new KeyboardButtonPollType('test'); $webApp = new WebAppInfo('https://example.com/test'); $button = new KeyboardButton( @@ -56,6 +59,7 @@ public function testFilled(): void $webApp, '5368324170671202286', 'primary', + $requestManagedBot, ); assertSame('test', $button->text); @@ -63,6 +67,7 @@ public function testFilled(): void assertSame('primary', $button->style); assertSame($requestUsers, $button->requestUsers); assertSame($requestChat, $button->requestChat); + assertSame($requestManagedBot, $button->requestManagedBot); assertTrue($button->requestContact); assertFalse($button->requestLocation); assertSame($requestPoll, $button->requestPoll); @@ -75,6 +80,7 @@ public function testFilled(): void 'style' => 'primary', 'request_users' => $requestUsers->toRequestArray(), 'request_chat' => $requestChat->toRequestArray(), + 'request_managed_bot' => $requestManagedBot->toRequestArray(), 'request_contact' => true, 'request_location' => false, 'request_poll' => $requestPoll->toRequestArray(), From d7340cbdfb0c7cb1ad9d9b08f8857a18bcc6729d Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 3 Apr 2026 19:52:02 +0300 Subject: [PATCH 03/18] Add `ManagedBotCreated` type. Add `managedBotCreated` field to `Message` type. --- CHANGELOG.md | 4 ++- src/Type/ManagedBotCreated.php | 17 +++++++++++ src/Type/Message.php | 1 + tests/Type/ManagedBotCreatedTest.php | 43 ++++++++++++++++++++++++++++ tests/Type/MessageTest.php | 10 +++++++ 5 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/Type/ManagedBotCreated.php create mode 100644 tests/Type/ManagedBotCreatedTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f96d198..090b8bc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,9 @@ - Enh #190: Open file in binary mode in `InputFile::fromLocalFile()` method. - New #191: Add `canManageBots` field to `User` type. - New #191: Add `KeyboardButtonRequestManagedBot` type. -- New #191: Add `request_managed_bot` field to `KeyboardButton` type. +- New #191: Add `requestManagedBot` field to `KeyboardButton` type. +- New #191: Add `ManagedBotCreated` type. +- New #191: Add `managedBotCreated` field to `Message` type. ## 0.17 March 1, 2026 diff --git a/src/Type/ManagedBotCreated.php b/src/Type/ManagedBotCreated.php new file mode 100644 index 00000000..66b8f9b3 --- /dev/null +++ b/src/Type/ManagedBotCreated.php @@ -0,0 +1,17 @@ +bot); + } + + public function testFromTelegramResult(): void + { + $managedBotCreated = (new ObjectFactory())->create([ + 'bot' => [ + 'id' => 1, + 'is_bot' => true, + 'first_name' => 'TestBot', + 'last_name' => 'Bot', + ], + ], null, ManagedBotCreated::class); + + assertInstanceOf(ManagedBotCreated::class, $managedBotCreated); + assertInstanceOf(User::class, $managedBotCreated->bot); + assertSame(1, $managedBotCreated->bot->id); + assertSame(true, $managedBotCreated->bot->isBot); + assertSame('TestBot', $managedBotCreated->bot->firstName); + assertSame('Bot', $managedBotCreated->bot->lastName); + } +} diff --git a/tests/Type/MessageTest.php b/tests/Type/MessageTest.php index 3e9b24ef..93c14100 100644 --- a/tests/Type/MessageTest.php +++ b/tests/Type/MessageTest.php @@ -146,6 +146,7 @@ public function testBase(): void assertNull($message->suggestedPostRefunded); assertNull($message->chatOwnerLeft); assertNull($message->chatOwnerChanged); + assertNull($message->managedBotCreated); } public function testFromTelegramResult(): void @@ -651,6 +652,13 @@ public function testFromTelegramResult(): void 'first_name' => 'Ivan', ], ], + 'managed_bot_created' => [ + 'bot' => [ + 'id' => 802, + 'is_bot' => true, + 'first_name' => 'ManagedBot', + ], + ], ], null, Message::class); assertSame(7, $message->messageId); @@ -792,5 +800,7 @@ public function testFromTelegramResult(): void assertSame('refund_reason', $message->suggestedPostRefunded?->reason); assertSame(800, $message->chatOwnerLeft?->newOwner?->id); assertSame(801, $message->chatOwnerChanged?->newOwner->id); + assertSame(802, $message->managedBotCreated?->bot->id); + assertSame('ManagedBot', $message->managedBotCreated?->bot->firstName); } } From 959cb3db951eb2abcce168587335a51017720cd4 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 3 Apr 2026 19:57:20 +0300 Subject: [PATCH 04/18] Add `ManagedBotUpdated` type. Add `managedBot` field to `Update` type. --- CHANGELOG.md | 2 + src/Type/ManagedBotUpdated.php | 18 +++++++++ src/Type/Update/Update.php | 2 + tests/Type/ManagedBotUpdatedTest.php | 56 ++++++++++++++++++++++++++++ tests/Type/Update/UpdateTest.php | 15 ++++++++ 5 files changed, 93 insertions(+) create mode 100644 src/Type/ManagedBotUpdated.php create mode 100644 tests/Type/ManagedBotUpdatedTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 090b8bc4..b1f2b208 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ - New #191: Add `requestManagedBot` field to `KeyboardButton` type. - New #191: Add `ManagedBotCreated` type. - New #191: Add `managedBotCreated` field to `Message` type. +- New #191: Add `ManagedBotUpdated` type. +- New #191: Add `managedBot` field to `Update` type. ## 0.17 March 1, 2026 diff --git a/src/Type/ManagedBotUpdated.php b/src/Type/ManagedBotUpdated.php new file mode 100644 index 00000000..fd5c247c --- /dev/null +++ b/src/Type/ManagedBotUpdated.php @@ -0,0 +1,18 @@ +user); + assertSame($bot, $managedBotUpdated->bot); + } + + public function testFromTelegramResult(): void + { + $managedBotUpdated = (new ObjectFactory())->create([ + 'user' => [ + 'id' => 1, + 'is_bot' => false, + 'first_name' => 'John', + 'last_name' => 'Doe', + ], + 'bot' => [ + 'id' => 2, + 'is_bot' => true, + 'first_name' => 'TestBot', + 'username' => 'test_bot', + ], + ], null, ManagedBotUpdated::class); + + assertInstanceOf(ManagedBotUpdated::class, $managedBotUpdated); + assertInstanceOf(User::class, $managedBotUpdated->user); + assertSame(1, $managedBotUpdated->user->id); + assertSame(false, $managedBotUpdated->user->isBot); + assertSame('John', $managedBotUpdated->user->firstName); + assertSame('Doe', $managedBotUpdated->user->lastName); + assertInstanceOf(User::class, $managedBotUpdated->bot); + assertSame(2, $managedBotUpdated->bot->id); + assertSame(true, $managedBotUpdated->bot->isBot); + assertSame('TestBot', $managedBotUpdated->bot->firstName); + assertSame('test_bot', $managedBotUpdated->bot->username); + } +} diff --git a/tests/Type/Update/UpdateTest.php b/tests/Type/Update/UpdateTest.php index 9d887696..9057f67f 100644 --- a/tests/Type/Update/UpdateTest.php +++ b/tests/Type/Update/UpdateTest.php @@ -46,6 +46,7 @@ public function testBase(): void assertNull($update->chatBoost); assertNull($update->removedChatBoost); assertNull($update->purchasedPaidMedia); + assertNull($update->managedBot); assertNull($update->getRaw()); assertNull($update->getRaw(true)); } @@ -335,6 +336,18 @@ public function testFromTelegramResult(): void ], ], ], + 'managed_bot' => [ + 'user' => [ + 'id' => 123, + 'is_bot' => false, + 'first_name' => 'Creator', + ], + 'bot' => [ + 'id' => 456, + 'is_bot' => true, + 'first_name' => 'ManagedBot', + ], + ], ]; $update = (new ObjectFactory())->create($data, null, Update::class); @@ -362,6 +375,8 @@ public function testFromTelegramResult(): void assertSame(23682, $update->chatBoost?->chat->id); assertSame(1735, $update->removedChatBoost?->chat->id); assertSame(1235, $update->purchasedPaidMedia->from->id); + assertSame(123, $update->managedBot?->user->id); + assertSame(456, $update->managedBot?->bot->id); assertNull($update->getRaw()); assertNull($update->getRaw(true)); } From 3fe300aa60402757449fcbd890e71249f73360f3 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 3 Apr 2026 20:03:46 +0300 Subject: [PATCH 05/18] Add `GetManagedBotToken` method --- CHANGELOG.md | 1 + src/Method/GetManagedBotToken.php | 41 +++++++++++++++++++++ src/TelegramBotApi.php | 9 +++++ tests/Method/GetManagedBotTokenTest.php | 38 +++++++++++++++++++ tests/TelegramBotApi/TelegramBotApiTest.php | 9 +++++ 5 files changed, 98 insertions(+) create mode 100644 src/Method/GetManagedBotToken.php create mode 100644 tests/Method/GetManagedBotTokenTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index b1f2b208..82291edc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - New #191: Add `managedBotCreated` field to `Message` type. - New #191: Add `ManagedBotUpdated` type. - New #191: Add `managedBot` field to `Update` type. +- New #191: Add `GetManagedBotToken` method. ## 0.17 March 1, 2026 diff --git a/src/Method/GetManagedBotToken.php b/src/Method/GetManagedBotToken.php new file mode 100644 index 00000000..29618db5 --- /dev/null +++ b/src/Method/GetManagedBotToken.php @@ -0,0 +1,41 @@ + + */ +final readonly class GetManagedBotToken implements MethodInterface +{ + public function __construct( + private int $userId, + ) {} + + public function getHttpMethod(): HttpMethod + { + return HttpMethod::POST; + } + + public function getApiMethod(): string + { + return 'getManagedBotToken'; + } + + public function getData(): array + { + return ['user_id' => $this->userId]; + } + + public function getResultType(): StringValue + { + return new StringValue(); + } +} diff --git a/src/TelegramBotApi.php b/src/TelegramBotApi.php index 532ef520..553afa1b 100644 --- a/src/TelegramBotApi.php +++ b/src/TelegramBotApi.php @@ -52,6 +52,7 @@ use Phptg\BotApi\Method\GetChatMenuButton; use Phptg\BotApi\Method\GetFile; use Phptg\BotApi\Method\GetForumTopicIconStickers; +use Phptg\BotApi\Method\GetManagedBotToken; use Phptg\BotApi\Method\GetMe; use Phptg\BotApi\Method\GetMyCommands; use Phptg\BotApi\Method\GetMyDefaultAdministratorRights; @@ -1350,6 +1351,14 @@ public function getMe(): FailResult|User return $this->call(new GetMe()); } + /** + * @see https://core.telegram.org/bots/api#getmanagedbottoken + */ + public function getManagedBotToken(int $userId): FailResult|string + { + return $this->call(new GetManagedBotToken($userId)); + } + /** * @see https://core.telegram.org/bots/api#getmycommands */ diff --git a/tests/Method/GetManagedBotTokenTest.php b/tests/Method/GetManagedBotTokenTest.php new file mode 100644 index 00000000..25c52ffe --- /dev/null +++ b/tests/Method/GetManagedBotTokenTest.php @@ -0,0 +1,38 @@ +getHttpMethod()); + assertSame('getManagedBotToken', $method->getApiMethod()); + assertSame( + [ + 'user_id' => 123, + ], + $method->getData(), + ); + } + + public function testPrepareResult(): void + { + $method = new GetManagedBotToken(123); + + $preparedResult = TestHelper::createSuccessStubApi('123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11')->call($method); + + assertSame('123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11', $preparedResult); + } +} diff --git a/tests/TelegramBotApi/TelegramBotApiTest.php b/tests/TelegramBotApi/TelegramBotApiTest.php index b057d3c9..66e87de2 100644 --- a/tests/TelegramBotApi/TelegramBotApiTest.php +++ b/tests/TelegramBotApi/TelegramBotApiTest.php @@ -1257,6 +1257,15 @@ public function testGetMe(): void assertSame(1, $result->id); } + public function testGetManagedBotToken(): void + { + $api = TestHelper::createSuccessStubApi('123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11'); + + $result = $api->getManagedBotToken(789); + + assertSame('123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11', $result); + } + public function testGetMyCommands(): void { $api = TestHelper::createSuccessStubApi([ From 4108f6bc30a7b063b3e8b2ff45bf2da736655baf Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 3 Apr 2026 20:08:21 +0300 Subject: [PATCH 06/18] Add `ReplaceManagedBotToken` method. --- CHANGELOG.md | 1 + src/Method/ReplaceManagedBotToken.php | 41 +++++++++++++++++++++ src/TelegramBotApi.php | 11 +++++- tests/Method/ReplaceManagedBotTokenTest.php | 38 +++++++++++++++++++ tests/TelegramBotApi/TelegramBotApiTest.php | 9 +++++ 5 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 src/Method/ReplaceManagedBotToken.php create mode 100644 tests/Method/ReplaceManagedBotTokenTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 82291edc..6f4fb20b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - New #191: Add `ManagedBotUpdated` type. - New #191: Add `managedBot` field to `Update` type. - New #191: Add `GetManagedBotToken` method. +- New #191: Add `ReplaceManagedBotToken` method. ## 0.17 March 1, 2026 diff --git a/src/Method/ReplaceManagedBotToken.php b/src/Method/ReplaceManagedBotToken.php new file mode 100644 index 00000000..96e94593 --- /dev/null +++ b/src/Method/ReplaceManagedBotToken.php @@ -0,0 +1,41 @@ + + */ +final readonly class ReplaceManagedBotToken implements MethodInterface +{ + public function __construct( + private int $userId, + ) {} + + public function getHttpMethod(): HttpMethod + { + return HttpMethod::POST; + } + + public function getApiMethod(): string + { + return 'replaceManagedBotToken'; + } + + public function getData(): array + { + return ['user_id' => $this->userId]; + } + + public function getResultType(): StringValue + { + return new StringValue(); + } +} diff --git a/src/TelegramBotApi.php b/src/TelegramBotApi.php index 553afa1b..e3b08c9b 100644 --- a/src/TelegramBotApi.php +++ b/src/TelegramBotApi.php @@ -82,8 +82,9 @@ use Phptg\BotApi\Method\PinChatMessage; use Phptg\BotApi\Method\PostStory; use Phptg\BotApi\Method\PromoteChatMember; -use Phptg\BotApi\Method\RepostStory; use Phptg\BotApi\Method\RemoveBusinessAccountProfilePhoto; +use Phptg\BotApi\Method\ReplaceManagedBotToken; +use Phptg\BotApi\Method\RepostStory; use Phptg\BotApi\Method\RemoveMyProfilePhoto; use Phptg\BotApi\Method\RemoveChatVerification; use Phptg\BotApi\Method\RemoveUserVerification; @@ -1768,6 +1769,14 @@ public function reopenGeneralForumTopic(int|string $chatId): FailResult|true ); } + /** + * @see https://core.telegram.org/bots/api#replacemanagedbottoken + */ + public function replaceManagedBotToken(int $userId): FailResult|string + { + return $this->call(new ReplaceManagedBotToken($userId)); + } + /** * @see https://core.telegram.org/bots/api#replacestickerinset */ diff --git a/tests/Method/ReplaceManagedBotTokenTest.php b/tests/Method/ReplaceManagedBotTokenTest.php new file mode 100644 index 00000000..89982f99 --- /dev/null +++ b/tests/Method/ReplaceManagedBotTokenTest.php @@ -0,0 +1,38 @@ +getHttpMethod()); + assertSame('replaceManagedBotToken', $method->getApiMethod()); + assertSame( + [ + 'user_id' => 123, + ], + $method->getData(), + ); + } + + public function testPrepareResult(): void + { + $method = new ReplaceManagedBotToken(123); + + $preparedResult = TestHelper::createSuccessStubApi('789012:XYZ-abc3456defGhi-lmn78O9p2q456rs22')->call($method); + + assertSame('789012:XYZ-abc3456defGhi-lmn78O9p2q456rs22', $preparedResult); + } +} diff --git a/tests/TelegramBotApi/TelegramBotApiTest.php b/tests/TelegramBotApi/TelegramBotApiTest.php index 66e87de2..a7c9aaf1 100644 --- a/tests/TelegramBotApi/TelegramBotApiTest.php +++ b/tests/TelegramBotApi/TelegramBotApiTest.php @@ -1740,6 +1740,15 @@ public function testReopenGeneralForumTopic(): void assertTrue($result); } + public function testReplaceManagedBotToken(): void + { + $api = TestHelper::createSuccessStubApi('789012:XYZ-abc3456defGhi-lmn78O9p2q456rs22'); + + $result = $api->replaceManagedBotToken(789); + + assertSame('789012:XYZ-abc3456defGhi-lmn78O9p2q456rs22', $result); + } + public function testReplaceStickerInSet(): void { $api = TestHelper::createSuccessStubApi(true); From 762a1382cb9e13da31d988ff60c3a7f8e705f0ed Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 3 Apr 2026 20:10:52 +0300 Subject: [PATCH 07/18] Add `PreparedKeyboardButton` type --- CHANGELOG.md | 1 + src/Type/PreparedKeyboardButton.php | 17 ++++++++++++ tests/Type/PreparedKeyboardButtonTest.php | 32 +++++++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 src/Type/PreparedKeyboardButton.php create mode 100644 tests/Type/PreparedKeyboardButtonTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f4fb20b..3419595d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - New #191: Add `managedBot` field to `Update` type. - New #191: Add `GetManagedBotToken` method. - New #191: Add `ReplaceManagedBotToken` method. +- New #191: Add `PreparedKeyboardButton` type. ## 0.17 March 1, 2026 diff --git a/src/Type/PreparedKeyboardButton.php b/src/Type/PreparedKeyboardButton.php new file mode 100644 index 00000000..3da8901e --- /dev/null +++ b/src/Type/PreparedKeyboardButton.php @@ -0,0 +1,17 @@ +id); + } + + public function testFromTelegramResult(): void + { + $button = (new ObjectFactory())->create([ + 'id' => 'button_456', + ], null, PreparedKeyboardButton::class); + + assertInstanceOf(PreparedKeyboardButton::class, $button); + assertSame('button_456', $button->id); + } +} From a49be822b843471a510032667c85360213152541 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 3 Apr 2026 20:16:55 +0300 Subject: [PATCH 08/18] Add `SavePreparedKeyboardButton` method. --- CHANGELOG.md | 1 + src/Method/SavePreparedKeyboardButton.php | 47 ++++++++++++++++++ src/TelegramBotApi.php | 11 +++++ .../Method/SavePreparedKeyboardButtonTest.php | 49 +++++++++++++++++++ tests/TelegramBotApi/TelegramBotApiTest.php | 15 ++++++ 5 files changed, 123 insertions(+) create mode 100644 src/Method/SavePreparedKeyboardButton.php create mode 100644 tests/Method/SavePreparedKeyboardButtonTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 3419595d..d4d45812 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - New #191: Add `GetManagedBotToken` method. - New #191: Add `ReplaceManagedBotToken` method. - New #191: Add `PreparedKeyboardButton` type. +- New #191: Add `SavePreparedKeyboardButton` method. ## 0.17 March 1, 2026 diff --git a/src/Method/SavePreparedKeyboardButton.php b/src/Method/SavePreparedKeyboardButton.php new file mode 100644 index 00000000..7f2d3904 --- /dev/null +++ b/src/Method/SavePreparedKeyboardButton.php @@ -0,0 +1,47 @@ + + */ +final readonly class SavePreparedKeyboardButton implements MethodInterface +{ + public function __construct( + private int $userId, + private KeyboardButton $button, + ) {} + + public function getHttpMethod(): HttpMethod + { + return HttpMethod::POST; + } + + public function getApiMethod(): string + { + return 'savePreparedKeyboardButton'; + } + + public function getData(): array + { + return [ + 'user_id' => $this->userId, + 'button' => $this->button->toRequestArray(), + ]; + } + + public function getResultType(): ObjectValue + { + return new ObjectValue(PreparedKeyboardButton::class); + } +} diff --git a/src/TelegramBotApi.php b/src/TelegramBotApi.php index e3b08c9b..89de6e8c 100644 --- a/src/TelegramBotApi.php +++ b/src/TelegramBotApi.php @@ -92,6 +92,7 @@ use Phptg\BotApi\Method\ReopenGeneralForumTopic; use Phptg\BotApi\Method\RestrictChatMember; use Phptg\BotApi\Method\RevokeChatInviteLink; +use Phptg\BotApi\Method\SavePreparedKeyboardButton; use Phptg\BotApi\Method\SendAnimation; use Phptg\BotApi\Method\SendAudio; use Phptg\BotApi\Method\SendChatAction; @@ -202,6 +203,8 @@ use Phptg\BotApi\Type\Inline\PreparedInlineMessage; use Phptg\BotApi\Type\Inline\SentWebAppMessage; use Phptg\BotApi\Type\InlineKeyboardMarkup; +use Phptg\BotApi\Type\KeyboardButton; +use Phptg\BotApi\Type\PreparedKeyboardButton; use Phptg\BotApi\Type\InputChecklist; use Phptg\BotApi\Type\InputFile; use Phptg\BotApi\Type\InputMedia; @@ -1816,6 +1819,14 @@ public function revokeChatInviteLink(int|string $chatId, string $inviteLink): Fa ); } + /** + * @see https://core.telegram.org/bots/api#savepreparedkeyboardbutton + */ + public function savePreparedKeyboardButton(int $userId, KeyboardButton $button): FailResult|PreparedKeyboardButton + { + return $this->call(new SavePreparedKeyboardButton($userId, $button)); + } + /** * @see https://core.telegram.org/bots/api#savepreparedinlinemessage */ diff --git a/tests/Method/SavePreparedKeyboardButtonTest.php b/tests/Method/SavePreparedKeyboardButtonTest.php new file mode 100644 index 00000000..ba8eeff9 --- /dev/null +++ b/tests/Method/SavePreparedKeyboardButtonTest.php @@ -0,0 +1,49 @@ +getHttpMethod()); + assertSame('savePreparedKeyboardButton', $method->getApiMethod()); + assertSame( + [ + 'user_id' => 123, + 'button' => [ + 'text' => 'Test Button', + ], + ], + $method->getData(), + ); + } + + public function testPrepareResult(): void + { + $button = new KeyboardButton('Test Button'); + $method = new SavePreparedKeyboardButton(123, $button); + + $preparedResult = TestHelper::createSuccessStubApi([ + 'id' => 'prepared_btn_789', + ])->call($method); + + assertInstanceOf(PreparedKeyboardButton::class, $preparedResult); + assertSame('prepared_btn_789', $preparedResult->id); + } +} diff --git a/tests/TelegramBotApi/TelegramBotApiTest.php b/tests/TelegramBotApi/TelegramBotApiTest.php index a7c9aaf1..baf41fa0 100644 --- a/tests/TelegramBotApi/TelegramBotApiTest.php +++ b/tests/TelegramBotApi/TelegramBotApiTest.php @@ -25,6 +25,7 @@ use Phptg\BotApi\Type\ChatPermissions; use Phptg\BotApi\Type\File; use Phptg\BotApi\Type\ForumTopic; +use Phptg\BotApi\Type\KeyboardButton; use Phptg\BotApi\Type\Game\GameHighScore; use Phptg\BotApi\Type\Inline\InlineQueryResultContact; use Phptg\BotApi\Type\Inline\InlineQueryResultGame; @@ -41,6 +42,7 @@ use Phptg\BotApi\Type\MessageId; use Phptg\BotApi\Type\OwnedGifts; use Phptg\BotApi\Type\Payment\StarTransactions; +use Phptg\BotApi\Type\PreparedKeyboardButton; use Phptg\BotApi\Type\StarAmount; use Phptg\BotApi\Type\Sticker\Gifts; use Phptg\BotApi\Type\Sticker\InputSticker; @@ -1792,6 +1794,19 @@ public function testRevokeChatInviteLink(): void assertSame(23, $result->creator->id); } + public function testSavePreparedKeyboardButton(): void + { + $api = TestHelper::createSuccessStubApi([ + 'id' => 'prepared_btn_123', + ]); + + $button = new KeyboardButton('Test Button'); + $result = $api->savePreparedKeyboardButton(456, $button); + + assertInstanceOf(PreparedKeyboardButton::class, $result); + assertSame('prepared_btn_123', $result->id); + } + public function testSavePreparedInlineMessage(): void { $api = TestHelper::createSuccessStubApi([ From 3aea0c5b0f2de9aa6d6e75ea3751a4db56b95a2b Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 3 Apr 2026 20:23:34 +0300 Subject: [PATCH 09/18] Replace `correctOptionId` field with `correctOptionIds` in `Poll` type. --- CHANGELOG.md | 1 + src/Type/Poll.php | 6 +++++- tests/Type/PollTest.php | 6 +++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4d45812..5e317386 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - New #191: Add `ReplaceManagedBotToken` method. - New #191: Add `PreparedKeyboardButton` type. - New #191: Add `SavePreparedKeyboardButton` method. +- Chg #191: Replace `correctOptionId` field with `correctOptionIds` in `Poll` type. ## 0.17 March 1, 2026 diff --git a/src/Type/Poll.php b/src/Type/Poll.php index dec68273..8b4caaa9 100644 --- a/src/Type/Poll.php +++ b/src/Type/Poll.php @@ -4,7 +4,9 @@ namespace Phptg\BotApi\Type; +use Phptg\BotApi\ParseResult\ValueProcessor\ArrayMap; use Phptg\BotApi\ParseResult\ValueProcessor\ArrayOfObjectsValue; +use Phptg\BotApi\ParseResult\ValueProcessor\IntegerValue; /** * @see https://core.telegram.org/bots/api#poll @@ -16,6 +18,7 @@ /** * @param MessageEntity[]|null $questionEntities * @param PollOption[] $options + * @param int[]|null $correctOptionIds * @param MessageEntity[]|null $explanationEntities */ public function __construct( @@ -30,7 +33,8 @@ public function __construct( public bool $allowsMultipleAnswers, #[ArrayOfObjectsValue(MessageEntity::class)] public ?array $questionEntities = null, - public ?int $correctOptionId = null, + #[ArrayMap(IntegerValue::class)] + public ?array $correctOptionIds = null, public ?string $explanation = null, #[ArrayOfObjectsValue(MessageEntity::class)] public ?array $explanationEntities = null, diff --git a/tests/Type/PollTest.php b/tests/Type/PollTest.php index c9602e7d..62879447 100644 --- a/tests/Type/PollTest.php +++ b/tests/Type/PollTest.php @@ -39,7 +39,7 @@ public function testBase(): void assertFalse($poll->isAnonymous); assertSame('regular', $poll->type); assertTrue($poll->allowsMultipleAnswers); - assertNull($poll->correctOptionId); + assertNull($poll->correctOptionIds); assertNull($poll->explanation); assertNull($poll->explanationEntities); assertNull($poll->openPeriod); @@ -66,7 +66,7 @@ public function testFromTelegramResult(): void 'type' => 'bold', ], ], - 'correct_option_id' => 23, + 'correct_option_ids' => [0, 2], 'explanation' => 'Because', 'explanation_entities' => [ [ @@ -94,7 +94,7 @@ public function testFromTelegramResult(): void assertCount(1, $poll->questionEntities); assertSame(35, $poll->questionEntities[0]->length); - assertSame(23, $poll->correctOptionId); + assertSame([0, 2], $poll->correctOptionIds); assertSame('Because', $poll->explanation); assertCount(1, $poll->explanationEntities); From e1025751cc2bbfc148aa17e1c96536c2e484e068 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 3 Apr 2026 20:31:56 +0300 Subject: [PATCH 10/18] Add `allowsRevoting`, `description` and `descriptionEntities` fields to `Poll` type --- CHANGELOG.md | 1 + 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 | 17 +++++++++++++++++ tests/Type/Update/UpdateTest.php | 1 + 8 files changed, 28 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e317386..71236714 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - New #191: Add `PreparedKeyboardButton` type. - New #191: Add `SavePreparedKeyboardButton` method. - Chg #191: Replace `correctOptionId` field with `correctOptionIds` in `Poll` type. +- New #191: Add `allowsRevoting`, `description` and `descriptionEntities` fields to `Poll` type. ## 0.17 March 1, 2026 diff --git a/src/Type/Poll.php b/src/Type/Poll.php index 8b4caaa9..c6bc57eb 100644 --- a/src/Type/Poll.php +++ b/src/Type/Poll.php @@ -20,6 +20,7 @@ * @param PollOption[] $options * @param int[]|null $correctOptionIds * @param MessageEntity[]|null $explanationEntities + * @param MessageEntity[]|null $descriptionEntities */ public function __construct( public string $id, @@ -31,6 +32,7 @@ public function __construct( public bool $isAnonymous, public string $type, public bool $allowsMultipleAnswers, + public bool $allowsRevoting, #[ArrayOfObjectsValue(MessageEntity::class)] public ?array $questionEntities = null, #[ArrayMap(IntegerValue::class)] @@ -40,5 +42,8 @@ public function __construct( public ?array $explanationEntities = null, public ?int $openPeriod = null, public ?int $closeDate = null, + public ?string $description = null, + #[ArrayOfObjectsValue(MessageEntity::class)] + public ?array $descriptionEntities = null, ) {} } diff --git a/tests/Method/UpdatingMessage/StopPollTest.php b/tests/Method/UpdatingMessage/StopPollTest.php index 82560aa9..78dfdc5d 100644 --- a/tests/Method/UpdatingMessage/StopPollTest.php +++ b/tests/Method/UpdatingMessage/StopPollTest.php @@ -61,6 +61,7 @@ public function testPrepareResult(): void 'is_anonymous' => false, 'type' => 'regular', 'allows_multiple_answers' => true, + 'allows_revoting' => false, ])->call($method); assertSame('12', $preparedResult->id); diff --git a/tests/TelegramBotApi/TelegramBotApiTest.php b/tests/TelegramBotApi/TelegramBotApiTest.php index baf41fa0..6c8163e0 100644 --- a/tests/TelegramBotApi/TelegramBotApiTest.php +++ b/tests/TelegramBotApi/TelegramBotApiTest.php @@ -2498,6 +2498,7 @@ public function testStopPoll(): void 'is_anonymous' => false, 'type' => 'regular', 'allows_multiple_answers' => true, + 'allows_revoting' => false, ]); $result = $api->stopPoll(1, 2); diff --git a/tests/Type/ExternalReplyInfoTest.php b/tests/Type/ExternalReplyInfoTest.php index 71b6aec1..b6a79694 100644 --- a/tests/Type/ExternalReplyInfoTest.php +++ b/tests/Type/ExternalReplyInfoTest.php @@ -182,6 +182,7 @@ public function testFromTelegramResult(): void 'is_anonymous' => false, 'type' => 'regular', 'allows_multiple_answers' => true, + 'allows_revoting' => false, ], 'venue' => [ 'location' => [ diff --git a/tests/Type/MessageTest.php b/tests/Type/MessageTest.php index 93c14100..70ef3fdd 100644 --- a/tests/Type/MessageTest.php +++ b/tests/Type/MessageTest.php @@ -335,6 +335,7 @@ public function testFromTelegramResult(): void 'is_anonymous' => false, 'type' => 'regular', 'allows_multiple_answers' => true, + 'allows_revoting' => false, ], 'venue' => [ 'location' => [ diff --git a/tests/Type/PollTest.php b/tests/Type/PollTest.php index 62879447..1f740df6 100644 --- a/tests/Type/PollTest.php +++ b/tests/Type/PollTest.php @@ -29,6 +29,7 @@ public function testBase(): void false, 'regular', true, + false, ); assertSame('12', $poll->id); @@ -39,11 +40,14 @@ public function testBase(): void assertFalse($poll->isAnonymous); assertSame('regular', $poll->type); assertTrue($poll->allowsMultipleAnswers); + assertFalse($poll->allowsRevoting); assertNull($poll->correctOptionIds); assertNull($poll->explanation); assertNull($poll->explanationEntities); assertNull($poll->openPeriod); assertNull($poll->closeDate); + assertNull($poll->description); + assertNull($poll->descriptionEntities); } public function testFromTelegramResult(): void @@ -59,6 +63,7 @@ public function testFromTelegramResult(): void 'is_anonymous' => false, 'type' => 'regular', 'allows_multiple_answers' => true, + 'allows_revoting' => true, 'question_entities' => [ [ 'offset' => 0, @@ -77,6 +82,14 @@ public function testFromTelegramResult(): void ], 'open_period' => 123, 'close_date' => 456, + 'description' => 'Poll description', + 'description_entities' => [ + [ + 'offset' => 0, + 'length' => 4, + 'type' => 'bold', + ], + ], ], null, Poll::class); assertSame('12', $poll->id); @@ -90,6 +103,7 @@ public function testFromTelegramResult(): void assertFalse($poll->isAnonymous); assertSame('regular', $poll->type); assertTrue($poll->allowsMultipleAnswers); + assertTrue($poll->allowsRevoting); assertCount(1, $poll->questionEntities); assertSame(35, $poll->questionEntities[0]->length); @@ -102,5 +116,8 @@ public function testFromTelegramResult(): void assertSame(123, $poll->openPeriod); assertSame(456, $poll->closeDate); + assertSame('Poll description', $poll->description); + assertCount(1, $poll->descriptionEntities); + assertSame(4, $poll->descriptionEntities[0]->length); } } diff --git a/tests/Type/Update/UpdateTest.php b/tests/Type/Update/UpdateTest.php index 9057f67f..6a422b66 100644 --- a/tests/Type/Update/UpdateTest.php +++ b/tests/Type/Update/UpdateTest.php @@ -227,6 +227,7 @@ public function testFromTelegramResult(): void 'is_anonymous' => false, 'type' => 'regular', 'allows_multiple_answers' => false, + 'allows_revoting' => true, ], 'poll_answer' => [ 'poll_id' => 'poll2', From 4a3f837a940a3ba171c979dabf94a8a3be009673 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 4 Apr 2026 10:46:02 +0300 Subject: [PATCH 11/18] Update `SendPoll` method --- CHANGELOG.md | 3 +++ src/Method/SendPoll.php | 25 +++++++++++++++++++++++-- src/TelegramBotApi.php | 20 ++++++++++++++++++-- tests/Method/SendPollTest.php | 19 +++++++++++++++++-- 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71236714..27d3700e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,9 @@ - New #191: Add `SavePreparedKeyboardButton` method. - Chg #191: Replace `correctOptionId` field with `correctOptionIds` in `Poll` type. - New #191: Add `allowsRevoting`, `description` and `descriptionEntities` fields to `Poll` type. +- Chg #191: Replace `correctOptionId` parameter with `correctOptionIds` in `SendPoll` method. +- New #191: Add `allowsRevoting`, `shuffleOptions`, `allowAddingOptions`, `hideResultsUntilCloses`, `description`, + `descriptionParseMode` and `descriptionEntities` parameters to `SendPoll` method. ## 0.17 March 1, 2026 diff --git a/src/Method/SendPoll.php b/src/Method/SendPoll.php index 8e85220c..ac9c6933 100644 --- a/src/Method/SendPoll.php +++ b/src/Method/SendPoll.php @@ -27,7 +27,9 @@ /** * @param InputPollOption[] $options * @param MessageEntity[]|null $questionEntities + * @param int[]|null $correctOptionIds * @param MessageEntity[]|null $explanationEntities + * @param MessageEntity[]|null $descriptionEntities */ public function __construct( private int|string $chatId, @@ -40,7 +42,7 @@ public function __construct( private ?bool $isAnonymous = null, private ?string $type = null, private ?bool $allowsMultipleAnswers = null, - private ?int $correctOptionId = null, + private ?array $correctOptionIds = null, private ?string $explanation = null, private ?string $explanationParseMode = null, private ?array $explanationEntities = null, @@ -53,6 +55,13 @@ public function __construct( private ?ReplyParameters $replyParameters = null, private InlineKeyboardMarkup|ReplyKeyboardMarkup|ReplyKeyboardRemove|ForceReply|null $replyMarkup = null, private ?bool $allowPaidBroadcast = null, + private ?bool $allowsRevoting = null, + private ?bool $shuffleOptions = null, + private ?bool $allowAddingOptions = null, + private ?bool $hideResultsUntilCloses = null, + private ?string $description = null, + private ?string $descriptionParseMode = null, + private ?array $descriptionEntities = null, ) {} public function getHttpMethod(): HttpMethod @@ -87,7 +96,11 @@ public function getData(): array 'is_anonymous' => $this->isAnonymous, 'type' => $this->type, 'allows_multiple_answers' => $this->allowsMultipleAnswers, - 'correct_option_id' => $this->correctOptionId, + 'allows_revoting' => $this->allowsRevoting, + 'shuffle_options' => $this->shuffleOptions, + 'allow_adding_options' => $this->allowAddingOptions, + 'hide_results_until_closes' => $this->hideResultsUntilCloses, + 'correct_option_ids' => $this->correctOptionIds, 'explanation' => $this->explanation, 'explanation_parse_mode' => $this->explanationParseMode, 'explanation_entities' => $this->explanationEntities === null @@ -99,6 +112,14 @@ public function getData(): array 'open_period' => $this->openPeriod, 'close_date' => $this->closeDate?->getTimestamp(), 'is_closed' => $this->isClosed, + 'description' => $this->description, + 'description_parse_mode' => $this->descriptionParseMode, + 'description_entities' => $this->descriptionEntities === null + ? null + : array_map( + static fn(MessageEntity $entity) => $entity->toRequestArray(), + $this->descriptionEntities, + ), 'disable_notification' => $this->disableNotification, 'protect_content' => $this->protectContent, 'allow_paid_broadcast' => $this->allowPaidBroadcast, diff --git a/src/TelegramBotApi.php b/src/TelegramBotApi.php index 89de6e8c..e4c7e1ee 100644 --- a/src/TelegramBotApi.php +++ b/src/TelegramBotApi.php @@ -2505,7 +2505,9 @@ public function sendPhoto( /** * @param InputPollOption[] $options * @param MessageEntity[]|null $questionEntities + * @param int[]|null $correctOptionIds * @param MessageEntity[]|null $explanationEntities + * @param MessageEntity[]|null $descriptionEntities * * @see https://core.telegram.org/bots/api#sendpoll */ @@ -2520,7 +2522,7 @@ public function sendPoll( ?bool $isAnonymous = null, ?string $type = null, ?bool $allowsMultipleAnswers = null, - ?int $correctOptionId = null, + ?array $correctOptionIds = null, ?string $explanation = null, ?string $explanationParseMode = null, ?array $explanationEntities = null, @@ -2533,6 +2535,13 @@ public function sendPoll( ?ReplyParameters $replyParameters = null, InlineKeyboardMarkup|ReplyKeyboardMarkup|ReplyKeyboardRemove|ForceReply|null $replyMarkup = null, ?bool $allowPaidBroadcast = null, + ?bool $allowsRevoting = null, + ?bool $shuffleOptions = null, + ?bool $allowAddingOptions = null, + ?bool $hideResultsUntilCloses = null, + ?string $description = null, + ?string $descriptionParseMode = null, + ?array $descriptionEntities = null, ): FailResult|Message { return $this->call( new SendPoll( @@ -2546,7 +2555,7 @@ public function sendPoll( $isAnonymous, $type, $allowsMultipleAnswers, - $correctOptionId, + $correctOptionIds, $explanation, $explanationParseMode, $explanationEntities, @@ -2559,6 +2568,13 @@ public function sendPoll( $replyParameters, $replyMarkup, $allowPaidBroadcast, + $allowsRevoting, + $shuffleOptions, + $allowAddingOptions, + $hideResultsUntilCloses, + $description, + $descriptionParseMode, + $descriptionEntities, ), ); } diff --git a/tests/Method/SendPollTest.php b/tests/Method/SendPollTest.php index af19b264..bf0e555b 100644 --- a/tests/Method/SendPollTest.php +++ b/tests/Method/SendPollTest.php @@ -45,6 +45,7 @@ public function testFull(): void $option2 = new InputPollOption('Bad'); $messageEntity1 = new MessageEntity('bold', 0, 5); $messageEntity2 = new MessageEntity('bold', 1, 3); + $messageEntity3 = new MessageEntity('italic', 2, 4); $date = new DateTimeImmutable(); $replyParameters = new ReplyParameters(23); $replyMarkup = new ForceReply(); @@ -59,7 +60,7 @@ public function testFull(): void true, 'quiz', false, - 23, + [0, 1], 'Good explanation', 'Markdown', [$messageEntity2], @@ -72,6 +73,13 @@ public function testFull(): void $replyParameters, $replyMarkup, true, + true, + true, + true, + true, + 'Poll description', + 'HTML', + [$messageEntity3], ); assertSame(HttpMethod::POST, $method->getHttpMethod()); @@ -91,13 +99,20 @@ public function testFull(): void 'is_anonymous' => true, 'type' => 'quiz', 'allows_multiple_answers' => false, - 'correct_option_id' => 23, + 'allows_revoting' => true, + 'shuffle_options' => true, + 'allow_adding_options' => true, + 'hide_results_until_closes' => true, + 'correct_option_ids' => [0, 1], 'explanation' => 'Good explanation', 'explanation_parse_mode' => 'Markdown', 'explanation_entities' => [$messageEntity2->toRequestArray()], 'open_period' => 300, 'close_date' => $date->getTimestamp(), 'is_closed' => true, + 'description' => 'Poll description', + 'description_parse_mode' => 'HTML', + 'description_entities' => [$messageEntity3->toRequestArray()], 'disable_notification' => false, 'protect_content' => false, 'allow_paid_broadcast' => true, From 1205e8a622f39b184e3d602eae97027b72915f0c Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 4 Apr 2026 10:51:37 +0300 Subject: [PATCH 12/18] Add `persistentId`, `addedByUser`, `addedByChat` and `additionDate` fields to `PollOption` type --- CHANGELOG.md | 1 + src/Type/PollOption.php | 4 ++++ tests/Method/UpdatingMessage/StopPollTest.php | 2 +- tests/TelegramBotApi/TelegramBotApiTest.php | 2 +- tests/Type/PollOptionTest.php | 22 ++++++++++++++++++- tests/Type/PollTest.php | 4 ++-- tests/Type/Update/UpdateTest.php | 4 ++-- 7 files changed, 32 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27d3700e..f5754351 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - Chg #191: Replace `correctOptionId` parameter with `correctOptionIds` in `SendPoll` method. - New #191: Add `allowsRevoting`, `shuffleOptions`, `allowAddingOptions`, `hideResultsUntilCloses`, `description`, `descriptionParseMode` and `descriptionEntities` parameters to `SendPoll` method. +- New #191: Add `persistentId`, `addedByUser`, `addedByChat` and `additionDate` fields to `PollOption` type. ## 0.17 March 1, 2026 diff --git a/src/Type/PollOption.php b/src/Type/PollOption.php index 78265909..1369a7a6 100644 --- a/src/Type/PollOption.php +++ b/src/Type/PollOption.php @@ -17,9 +17,13 @@ * @param MessageEntity[]|null $textEntities */ public function __construct( + public string $persistentId, public string $text, public int $voterCount, #[ArrayOfObjectsValue(MessageEntity::class)] public ?array $textEntities = null, + public ?User $addedByUser = null, + public ?Chat $addedByChat = null, + public ?int $additionDate = null, ) {} } diff --git a/tests/Method/UpdatingMessage/StopPollTest.php b/tests/Method/UpdatingMessage/StopPollTest.php index 78dfdc5d..9ce26e8e 100644 --- a/tests/Method/UpdatingMessage/StopPollTest.php +++ b/tests/Method/UpdatingMessage/StopPollTest.php @@ -54,7 +54,7 @@ public function testPrepareResult(): void 'id' => '12', 'question' => 'Why?', 'options' => [ - ['text' => 'One', 'voter_count' => 12], + ['persistent_id' => 'pid1', 'text' => 'One', 'voter_count' => 12], ], 'total_voter_count' => 42, 'is_closed' => true, diff --git a/tests/TelegramBotApi/TelegramBotApiTest.php b/tests/TelegramBotApi/TelegramBotApiTest.php index 6c8163e0..662d513b 100644 --- a/tests/TelegramBotApi/TelegramBotApiTest.php +++ b/tests/TelegramBotApi/TelegramBotApiTest.php @@ -2491,7 +2491,7 @@ public function testStopPoll(): void 'id' => '12', 'question' => 'Why?', 'options' => [ - ['text' => 'One', 'voter_count' => 12], + ['persistent_id' => 'pid1', 'text' => 'One', 'voter_count' => 12], ], 'total_voter_count' => 42, 'is_closed' => true, diff --git a/tests/Type/PollOptionTest.php b/tests/Type/PollOptionTest.php index ce99470c..0e31244c 100644 --- a/tests/Type/PollOptionTest.php +++ b/tests/Type/PollOptionTest.php @@ -16,16 +16,21 @@ final class PollOptionTest extends TestCase { public function testBase(): void { - $option = new PollOption('A', 25); + $option = new PollOption('pid1', 'A', 25); + assertSame('pid1', $option->persistentId); assertSame('A', $option->text); assertSame(25, $option->voterCount); assertNull($option->textEntities); + assertNull($option->addedByUser); + assertNull($option->addedByChat); + assertNull($option->additionDate); } public function testFromTelegramResult(): void { $option = (new ObjectFactory())->create([ + 'persistent_id' => 'pid1', 'text' => 'A', 'voter_count' => 25, 'text_entities' => [ @@ -35,12 +40,27 @@ public function testFromTelegramResult(): void 'type' => 'bold', ], ], + 'added_by_user' => [ + 'id' => 42, + 'is_bot' => false, + 'first_name' => 'John', + ], + 'added_by_chat' => [ + 'id' => 100, + 'type' => 'group', + ], + 'addition_date' => 1700000000, ], null, PollOption::class); + assertSame('pid1', $option->persistentId); assertSame('A', $option->text); assertSame(25, $option->voterCount); assertCount(1, $option->textEntities); assertSame(23, $option->textEntities[0]->offset); + + assertSame(42, $option->addedByUser->id); + assertSame(100, $option->addedByChat->id); + assertSame(1700000000, $option->additionDate); } } diff --git a/tests/Type/PollTest.php b/tests/Type/PollTest.php index 1f740df6..df3f5b40 100644 --- a/tests/Type/PollTest.php +++ b/tests/Type/PollTest.php @@ -19,7 +19,7 @@ final class PollTest extends TestCase { public function testBase(): void { - $option = new PollOption('One', 12); + $option = new PollOption('pid1', 'One', 12); $poll = new Poll( '12', 'Why?', @@ -56,7 +56,7 @@ public function testFromTelegramResult(): void 'id' => '12', 'question' => 'Why?', 'options' => [ - ['text' => 'One', 'voter_count' => 12], + ['persistent_id' => 'pid1', 'text' => 'One', 'voter_count' => 12], ], 'total_voter_count' => 42, 'is_closed' => true, diff --git a/tests/Type/Update/UpdateTest.php b/tests/Type/Update/UpdateTest.php index 6a422b66..8fcd6d1f 100644 --- a/tests/Type/Update/UpdateTest.php +++ b/tests/Type/Update/UpdateTest.php @@ -219,8 +219,8 @@ public function testFromTelegramResult(): void 'id' => 'poll1', 'question' => 'Question', 'options' => [ - ['text' => 'Option 1', 'voter_count' => 7], - ['text' => 'Option 2', 'voter_count' => 5], + ['persistent_id' => 'pid1', 'text' => 'Option 1', 'voter_count' => 7], + ['persistent_id' => 'pid2', 'text' => 'Option 2', 'voter_count' => 5], ], 'total_voter_count' => 12, 'is_closed' => true, From 4751828a878bcde5123177b6d5b51165e370fe7b Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 4 Apr 2026 10:53:57 +0300 Subject: [PATCH 13/18] Add `optionPersistentIds` field to `PollAnswer` type. --- CHANGELOG.md | 1 + src/Type/PollAnswer.php | 4 ++++ tests/Type/PollAnswerTest.php | 5 ++++- tests/Type/Update/UpdateTest.php | 1 + 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5754351..2674570f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - New #191: Add `allowsRevoting`, `shuffleOptions`, `allowAddingOptions`, `hideResultsUntilCloses`, `description`, `descriptionParseMode` and `descriptionEntities` parameters to `SendPoll` method. - New #191: Add `persistentId`, `addedByUser`, `addedByChat` and `additionDate` fields to `PollOption` type. +- New #191: Add `optionPersistentIds` field to `PollAnswer` type. ## 0.17 March 1, 2026 diff --git a/src/Type/PollAnswer.php b/src/Type/PollAnswer.php index 76fee261..b229238c 100644 --- a/src/Type/PollAnswer.php +++ b/src/Type/PollAnswer.php @@ -6,6 +6,7 @@ use Phptg\BotApi\ParseResult\ValueProcessor\ArrayMap; use Phptg\BotApi\ParseResult\ValueProcessor\IntegerValue; +use Phptg\BotApi\ParseResult\ValueProcessor\StringValue; /** * @see https://core.telegram.org/bots/api#pollanswer @@ -16,11 +17,14 @@ { /** * @param int[] $optionIds + * @param string[] $optionPersistentIds */ public function __construct( public string $pollId, #[ArrayMap(IntegerValue::class)] public array $optionIds, + #[ArrayMap(StringValue::class)] + public array $optionPersistentIds, public ?Chat $voterChat = null, public ?User $user = null, ) {} diff --git a/tests/Type/PollAnswerTest.php b/tests/Type/PollAnswerTest.php index a425b32c..522c33c4 100644 --- a/tests/Type/PollAnswerTest.php +++ b/tests/Type/PollAnswerTest.php @@ -15,10 +15,11 @@ final class PollAnswerTest extends TestCase { public function testBase(): void { - $answer = new PollAnswer('sadg', [2, 4]); + $answer = new PollAnswer('sadg', [2, 4], ['pid2', 'pid4']); assertSame('sadg', $answer->pollId); assertSame([2, 4], $answer->optionIds); + assertSame(['pid2', 'pid4'], $answer->optionPersistentIds); assertNull($answer->voterChat); assertNull($answer->user); } @@ -28,6 +29,7 @@ public function testFromTelegramResult(): void $answer = (new ObjectFactory())->create([ 'poll_id' => 'sadg', 'option_ids' => [2, 4], + 'option_persistent_ids' => ['pid2', 'pid4'], 'voter_chat' => [ 'id' => 42, 'type' => 'private', @@ -41,6 +43,7 @@ public function testFromTelegramResult(): void assertSame('sadg', $answer->pollId); assertSame([2, 4], $answer->optionIds); + assertSame(['pid2', 'pid4'], $answer->optionPersistentIds); assertSame(42, $answer->voterChat?->id); assertSame(43, $answer->user?->id); } diff --git a/tests/Type/Update/UpdateTest.php b/tests/Type/Update/UpdateTest.php index 8fcd6d1f..56b2754f 100644 --- a/tests/Type/Update/UpdateTest.php +++ b/tests/Type/Update/UpdateTest.php @@ -232,6 +232,7 @@ public function testFromTelegramResult(): void 'poll_answer' => [ 'poll_id' => 'poll2', 'option_ids' => [0], + 'option_persistent_ids' => ['pid1'], ], 'my_chat_member' => [ 'chat' => [ From 974851f204723b68cc22f906155d7c46d124f0d0 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 4 Apr 2026 10:59:54 +0300 Subject: [PATCH 14/18] Add `PollOptionAdded` and `PollOptionDeleted` type. Add `pollOptionAdded` and `pollOptionDeleted` fields to `Message` type. --- CHANGELOG.md | 2 + src/Type/Message.php | 2 + src/Type/PollOptionAdded.php | 28 ++++++++++++++ src/Type/PollOptionDeleted.php | 28 ++++++++++++++ tests/Type/MessageTest.php | 14 +++++++ tests/Type/PollOptionAddedTest.php | 56 ++++++++++++++++++++++++++++ tests/Type/PollOptionDeletedTest.php | 56 ++++++++++++++++++++++++++++ 7 files changed, 186 insertions(+) create mode 100644 src/Type/PollOptionAdded.php create mode 100644 src/Type/PollOptionDeleted.php create mode 100644 tests/Type/PollOptionAddedTest.php create mode 100644 tests/Type/PollOptionDeletedTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 2674570f..94f7996d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ `descriptionParseMode` and `descriptionEntities` parameters to `SendPoll` method. - New #191: Add `persistentId`, `addedByUser`, `addedByChat` and `additionDate` fields to `PollOption` type. - New #191: Add `optionPersistentIds` field to `PollAnswer` type. +- New #191: Add `PollOptionAdded` and `PollOptionDeleted` type. +- New #191: Add `pollOptionAdded` and `pollOptionDeleted` fields to `Message` type. ## 0.17 March 1, 2026 diff --git a/src/Type/Message.php b/src/Type/Message.php index 4c4afd7d..a48cab5c 100644 --- a/src/Type/Message.php +++ b/src/Type/Message.php @@ -142,5 +142,7 @@ public function __construct( public ?ChatOwnerLeft $chatOwnerLeft = null, public ?ChatOwnerChanged $chatOwnerChanged = null, public ?ManagedBotCreated $managedBotCreated = null, + public ?PollOptionAdded $pollOptionAdded = null, + public ?PollOptionDeleted $pollOptionDeleted = null, ) {} } diff --git a/src/Type/PollOptionAdded.php b/src/Type/PollOptionAdded.php new file mode 100644 index 00000000..cf63c1d2 --- /dev/null +++ b/src/Type/PollOptionAdded.php @@ -0,0 +1,28 @@ +chatOwnerLeft); assertNull($message->chatOwnerChanged); assertNull($message->managedBotCreated); + assertNull($message->pollOptionAdded); + assertNull($message->pollOptionDeleted); } public function testFromTelegramResult(): void @@ -660,6 +662,14 @@ public function testFromTelegramResult(): void 'first_name' => 'ManagedBot', ], ], + 'poll_option_added' => [ + 'option_persistent_id' => 'pid1', + 'option_text' => 'New option', + ], + 'poll_option_deleted' => [ + 'option_persistent_id' => 'pid2', + 'option_text' => 'Deleted option', + ], ], null, Message::class); assertSame(7, $message->messageId); @@ -803,5 +813,9 @@ public function testFromTelegramResult(): void assertSame(801, $message->chatOwnerChanged?->newOwner->id); assertSame(802, $message->managedBotCreated?->bot->id); assertSame('ManagedBot', $message->managedBotCreated?->bot->firstName); + assertSame('pid1', $message->pollOptionAdded?->optionPersistentId); + assertSame('New option', $message->pollOptionAdded?->optionText); + assertSame('pid2', $message->pollOptionDeleted?->optionPersistentId); + assertSame('Deleted option', $message->pollOptionDeleted?->optionText); } } diff --git a/tests/Type/PollOptionAddedTest.php b/tests/Type/PollOptionAddedTest.php new file mode 100644 index 00000000..cedc2a59 --- /dev/null +++ b/tests/Type/PollOptionAddedTest.php @@ -0,0 +1,56 @@ +optionPersistentId); + assertSame('Option text', $pollOptionAdded->optionText); + assertNull($pollOptionAdded->pollMessage); + assertNull($pollOptionAdded->optionTextEntities); + } + + public function testFromTelegramResult(): void + { + $pollOptionAdded = (new ObjectFactory())->create([ + 'option_persistent_id' => 'pid1', + 'option_text' => 'Option text', + 'poll_message' => [ + 'message_id' => 1, + 'date' => 1620000000, + 'chat' => ['id' => 10, 'type' => 'private'], + ], + 'option_text_entities' => [ + [ + 'type' => 'bold', + 'offset' => 0, + 'length' => 6, + ], + ], + ], null, PollOptionAdded::class); + + assertInstanceOf(PollOptionAdded::class, $pollOptionAdded); + assertSame('pid1', $pollOptionAdded->optionPersistentId); + assertSame('Option text', $pollOptionAdded->optionText); + assertInstanceOf(Message::class, $pollOptionAdded->pollMessage); + assertSame(1, $pollOptionAdded->pollMessage->messageId); + assertCount(1, $pollOptionAdded->optionTextEntities); + assertSame('bold', $pollOptionAdded->optionTextEntities[0]->type); + } +} diff --git a/tests/Type/PollOptionDeletedTest.php b/tests/Type/PollOptionDeletedTest.php new file mode 100644 index 00000000..0443420c --- /dev/null +++ b/tests/Type/PollOptionDeletedTest.php @@ -0,0 +1,56 @@ +optionPersistentId); + assertSame('Option text', $pollOptionDeleted->optionText); + assertNull($pollOptionDeleted->pollMessage); + assertNull($pollOptionDeleted->optionTextEntities); + } + + public function testFromTelegramResult(): void + { + $pollOptionDeleted = (new ObjectFactory())->create([ + 'option_persistent_id' => 'pid1', + 'option_text' => 'Option text', + 'poll_message' => [ + 'message_id' => 1, + 'date' => 1620000000, + 'chat' => ['id' => 10, 'type' => 'private'], + ], + 'option_text_entities' => [ + [ + 'type' => 'bold', + 'offset' => 0, + 'length' => 6, + ], + ], + ], null, PollOptionDeleted::class); + + assertInstanceOf(PollOptionDeleted::class, $pollOptionDeleted); + assertSame('pid1', $pollOptionDeleted->optionPersistentId); + assertSame('Option text', $pollOptionDeleted->optionText); + assertInstanceOf(Message::class, $pollOptionDeleted->pollMessage); + assertSame(1, $pollOptionDeleted->pollMessage->messageId); + assertCount(1, $pollOptionDeleted->optionTextEntities); + assertSame('bold', $pollOptionDeleted->optionTextEntities[0]->type); + } +} From 4d8873e672b6fa7974c4a3b80841feb567963c87 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 4 Apr 2026 11:01:52 +0300 Subject: [PATCH 15/18] Add `pollOptionId` field to `ReplyParameters` type --- CHANGELOG.md | 1 + src/Type/ReplyParameters.php | 2 ++ tests/Type/ReplyParametersTest.php | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94f7996d..c9c554cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ - New #191: Add `optionPersistentIds` field to `PollAnswer` type. - New #191: Add `PollOptionAdded` and `PollOptionDeleted` type. - New #191: Add `pollOptionAdded` and `pollOptionDeleted` fields to `Message` type. +- New #191: Add `pollOptionId` field to `ReplyParameters` type. ## 0.17 March 1, 2026 diff --git a/src/Type/ReplyParameters.php b/src/Type/ReplyParameters.php index a6771c75..803f5281 100644 --- a/src/Type/ReplyParameters.php +++ b/src/Type/ReplyParameters.php @@ -23,6 +23,7 @@ public function __construct( public ?array $quoteEntities = null, public ?int $quotePosition = null, public ?int $checklistTaskId = null, + public ?string $pollOptionId = null, ) {} public function toRequestArray(): array @@ -40,6 +41,7 @@ public function toRequestArray(): array ), 'quote_position' => $this->quotePosition, 'checklist_task_id' => $this->checklistTaskId, + 'poll_option_id' => $this->pollOptionId, ], static fn(mixed $value): bool => $value !== null, ); diff --git a/tests/Type/ReplyParametersTest.php b/tests/Type/ReplyParametersTest.php index efa63e46..4a333a4c 100644 --- a/tests/Type/ReplyParametersTest.php +++ b/tests/Type/ReplyParametersTest.php @@ -26,6 +26,7 @@ public function testBase(): void assertNull($replyParameters->quoteEntities); assertNull($replyParameters->quotePosition); assertNull($replyParameters->checklistTaskId); + assertNull($replyParameters->pollOptionId); assertSame( [ @@ -47,6 +48,7 @@ public function testFilled(): void [$quoteEntity], 23, 456, + 'pid1', ); assertSame(99, $replyParameters->messageId); @@ -57,6 +59,7 @@ public function testFilled(): void assertSame([$quoteEntity], $replyParameters->quoteEntities); assertSame(23, $replyParameters->quotePosition); assertSame(456, $replyParameters->checklistTaskId); + assertSame('pid1', $replyParameters->pollOptionId); assertSame( [ @@ -68,6 +71,7 @@ public function testFilled(): void 'quote_entities' => [$quoteEntity->toRequestArray()], 'quote_position' => 23, 'checklist_task_id' => 456, + 'poll_option_id' => 'pid1', ], $replyParameters->toRequestArray(), ); From e2f78842d86592c8ed3dd6a43aa14b7db2cc5353 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 4 Apr 2026 11:03:06 +0300 Subject: [PATCH 16/18] Add `replyToPollOptionId` field to `Message` type --- CHANGELOG.md | 1 + src/Type/Message.php | 1 + tests/Type/MessageTest.php | 3 +++ 3 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9c554cb..ba9c7247 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - New #191: Add `PollOptionAdded` and `PollOptionDeleted` type. - New #191: Add `pollOptionAdded` and `pollOptionDeleted` fields to `Message` type. - New #191: Add `pollOptionId` field to `ReplyParameters` type. +- New #191: Add `replyToPollOptionId` field to `Message` type. ## 0.17 March 1, 2026 diff --git a/src/Type/Message.php b/src/Type/Message.php index a48cab5c..04a531bb 100644 --- a/src/Type/Message.php +++ b/src/Type/Message.php @@ -131,6 +131,7 @@ public function __construct( public ?ChecklistTasksDone $checklistTasksDone = null, public ?ChecklistTasksAdded $checklistTasksAdded = null, public ?int $replyToChecklistTaskId = null, + public ?string $replyToPollOptionId = null, public ?DirectMessagesTopic $directMessagesTopic = null, public ?true $isPaidPost = null, public ?SuggestedPostInfo $suggestedPostInfo = null, diff --git a/tests/Type/MessageTest.php b/tests/Type/MessageTest.php index 6dab27fb..7d7e3699 100644 --- a/tests/Type/MessageTest.php +++ b/tests/Type/MessageTest.php @@ -137,6 +137,7 @@ public function testBase(): void assertNull($message->checklistTasksDone); assertNull($message->checklistTasksAdded); assertNull($message->replyToChecklistTaskId); + assertNull($message->replyToPollOptionId); assertNull($message->directMessagesTopic); assertNull($message->suggestedPostInfo); assertNull($message->suggestedPostApproved); @@ -215,6 +216,7 @@ public function testFromTelegramResult(): void 'id' => 8863, ], 'reply_to_checklist_task_id' => 789, + 'reply_to_poll_option_id' => 'pid1', 'via_bot' => [ 'id' => 127, 'is_bot' => false, @@ -799,6 +801,7 @@ public function testFromTelegramResult(): void assertInstanceOf(ChecklistTasksAdded::class, $message->checklistTasksAdded); assertCount(2, $message->checklistTasksAdded->tasks); assertSame(789, $message->replyToChecklistTaskId); + assertSame('pid1', $message->replyToPollOptionId); assertSame(12345, $message->directMessagesTopic?->topicId); assertSame('pending', $message->suggestedPostInfo?->state); assertSame('XTR', $message->suggestedPostInfo?->price?->currency); From f3a78f6f9fa07ce77441b899559afc3b1ff26d06 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 4 Apr 2026 11:08:49 +0300 Subject: [PATCH 17/18] readme&changelog --- CHANGELOG.md | 18 ++++++------------ README.md | 2 +- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba9c7247..fa9f851b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,17 +3,14 @@ ## 0.17.1 under development - Enh #190: Open file in binary mode in `InputFile::fromLocalFile()` method. -- New #191: Add `canManageBots` field to `User` type. -- New #191: Add `KeyboardButtonRequestManagedBot` type. +- New #191: Add `GetManagedBotToken`, `ReplaceManagedBotToken` and `SavePreparedKeyboardButton` methods. +- New #191: Add `KeyboardButtonRequestManagedBot`, `ManagedBotCreated`, `ManagedBotUpdated`, `PreparedKeyboardButton`, + `PollOptionAdded` and `PollOptionDeleted` types. - New #191: Add `requestManagedBot` field to `KeyboardButton` type. -- New #191: Add `ManagedBotCreated` type. -- New #191: Add `managedBotCreated` field to `Message` type. -- New #191: Add `ManagedBotUpdated` type. +- New #191: Add `canManageBots` field to `User` type. +- New #191: Add `managedBotCreated`, `pollOptionAdded`, `pollOptionDeleted` and `replyToPollOptionId` field to `Message` + type. - New #191: Add `managedBot` field to `Update` type. -- New #191: Add `GetManagedBotToken` method. -- New #191: Add `ReplaceManagedBotToken` method. -- New #191: Add `PreparedKeyboardButton` type. -- New #191: Add `SavePreparedKeyboardButton` method. - Chg #191: Replace `correctOptionId` field with `correctOptionIds` in `Poll` type. - New #191: Add `allowsRevoting`, `description` and `descriptionEntities` fields to `Poll` type. - Chg #191: Replace `correctOptionId` parameter with `correctOptionIds` in `SendPoll` method. @@ -21,10 +18,7 @@ `descriptionParseMode` and `descriptionEntities` parameters to `SendPoll` method. - New #191: Add `persistentId`, `addedByUser`, `addedByChat` and `additionDate` fields to `PollOption` type. - New #191: Add `optionPersistentIds` field to `PollAnswer` type. -- New #191: Add `PollOptionAdded` and `PollOptionDeleted` type. -- New #191: Add `pollOptionAdded` and `pollOptionDeleted` fields to `Message` type. - New #191: Add `pollOptionId` field to `ReplyParameters` type. -- New #191: Add `replyToPollOptionId` field to `Message` type. ## 0.17 March 1, 2026 diff --git a/README.md b/README.md index 40a284d2..deb2cc43 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.5 (March 1, 2026) is **fully supported**. +✔️ Telegram Bot API 9.6 (April 3, 2026) is **fully supported**. ♻️ **Zero dependencies** — no third-party libraries, only native PHP. From 006f38a3b8dfae708edee9663da11207c92a2486 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 4 Apr 2026 11:09:39 +0300 Subject: [PATCH 18/18] changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa9f851b..631d5271 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Telegram Bot API for PHP Change Log -## 0.17.1 under development +## 0.18 April 4, 2026 - Enh #190: Open file in binary mode in `InputFile::fromLocalFile()` method. - New #191: Add `GetManagedBotToken`, `ReplaceManagedBotToken` and `SavePreparedKeyboardButton` methods.