From e787948955d03b44382b9c2494db6bae81b7c013 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 9 Feb 2026 22:38:04 +0300 Subject: [PATCH 01/18] Add `allows_users_to_create_topics` 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 48edf35d..6efe3aa2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Telegram Bot API for PHP Change Log +## 0.14.1 under development + +- New #186: Add `allowsUsersToCreateTopics` field to `User` type. + ## 0.14 February 7, 2026 - New #182: Introduce resource readers that handle reading content from different types of resources stored in diff --git a/src/Type/User.php b/src/Type/User.php index b1f2394a..d4cdcc6b 100644 --- a/src/Type/User.php +++ b/src/Type/User.php @@ -26,6 +26,7 @@ public function __construct( public ?bool $canConnectToBusiness = null, public ?bool $hasMainWebApp = null, public ?bool $hasTopicsEnabled = null, + public ?bool $allowsUsersToCreateTopics = null, ) {} public function toRequestArray(): array @@ -46,6 +47,7 @@ public function toRequestArray(): array 'can_connect_to_business' => $this->canConnectToBusiness, 'has_main_web_app' => $this->hasMainWebApp, 'has_topics_enabled' => $this->hasTopicsEnabled, + 'allows_users_to_create_topics' => $this->allowsUsersToCreateTopics, ], static fn(mixed $value): bool => $value !== null, ); diff --git a/tests/Type/UserTest.php b/tests/Type/UserTest.php index 08b8a646..87939a05 100644 --- a/tests/Type/UserTest.php +++ b/tests/Type/UserTest.php @@ -32,6 +32,7 @@ public function testBase(): void assertNull($user->canConnectToBusiness); assertNull($user->hasMainWebApp); assertNull($user->hasTopicsEnabled); + assertNull($user->allowsUsersToCreateTopics); } public function testToRequestArray(): void @@ -51,6 +52,7 @@ public function testToRequestArray(): void true, false, true, + true, ); assertSame( @@ -69,6 +71,7 @@ public function testToRequestArray(): void 'can_connect_to_business' => true, 'has_main_web_app' => false, 'has_topics_enabled' => true, + 'allows_users_to_create_topics' => true, ], $user->toRequestArray(), ); @@ -91,6 +94,7 @@ public function testFromTelegramResult(): void 'can_connect_to_business' => true, 'has_main_web_app' => false, 'has_topics_enabled' => true, + 'allows_users_to_create_topics' => true, ], null, User::class); assertInstanceOf(User::class, $user); @@ -108,5 +112,6 @@ public function testFromTelegramResult(): void assertSame(true, $user->canConnectToBusiness); assertSame(false, $user->hasMainWebApp); assertSame(true, $user->hasTopicsEnabled); + assertSame(true, $user->allowsUsersToCreateTopics); } } From f11a43c36622f228af81bc05214334945aa61799 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 9 Feb 2026 22:44:15 +0300 Subject: [PATCH 02/18] Add `iconCustomEmojiId` and `style` fields to `KeyboardButton` and `InlineKeyboardButton` types. --- CHANGELOG.md | 2 ++ src/Type/InlineKeyboardButton.php | 4 ++++ src/Type/KeyboardButton.php | 4 ++++ tests/Type/InlineKeyboardButtonTest.php | 12 ++++++++++++ tests/Type/KeyboardButtonTest.php | 8 ++++++++ 5 files changed, 30 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6efe3aa2..8503d95f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## 0.14.1 under development - New #186: Add `allowsUsersToCreateTopics` field to `User` type. +- New #186: Add `iconCustomEmojiId` and `style` fields to `KeyboardButton` type. +- New #186: Add `iconCustomEmojiId` and `style` fields to `InlineKeyboardButton` type. ## 0.14 February 7, 2026 diff --git a/src/Type/InlineKeyboardButton.php b/src/Type/InlineKeyboardButton.php index 1fe7c673..8bbc9d2b 100644 --- a/src/Type/InlineKeyboardButton.php +++ b/src/Type/InlineKeyboardButton.php @@ -25,6 +25,8 @@ public function __construct( public ?CallbackGame $callbackGame = null, public ?bool $pay = null, public ?CopyTextButton $copyText = null, + public ?string $iconCustomEmojiId = null, + public ?string $style = null, ) {} public function toRequestArray(): array @@ -32,6 +34,8 @@ public function toRequestArray(): array return array_filter( [ 'text' => $this->text, + 'icon_custom_emoji_id' => $this->iconCustomEmojiId, + 'style' => $this->style, 'url' => $this->url, 'callback_data' => $this->callbackData, 'web_app' => $this->webApp?->toRequestArray(), diff --git a/src/Type/KeyboardButton.php b/src/Type/KeyboardButton.php index 89a0e25b..3e4ce7a3 100644 --- a/src/Type/KeyboardButton.php +++ b/src/Type/KeyboardButton.php @@ -19,6 +19,8 @@ public function __construct( public ?bool $requestLocation = null, public ?KeyboardButtonPollType $requestPoll = null, public ?WebAppInfo $webApp = null, + public ?string $iconCustomEmojiId = null, + public ?string $style = null, ) {} public function toRequestArray(): array @@ -26,6 +28,8 @@ public function toRequestArray(): array return array_filter( [ 'text' => $this->text, + 'icon_custom_emoji_id' => $this->iconCustomEmojiId, + 'style' => $this->style, 'request_users' => $this->requestUsers?->toRequestArray(), 'request_chat' => $this->requestChat?->toRequestArray(), 'request_contact' => $this->requestContact, diff --git a/tests/Type/InlineKeyboardButtonTest.php b/tests/Type/InlineKeyboardButtonTest.php index 6881db6a..fee9733b 100644 --- a/tests/Type/InlineKeyboardButtonTest.php +++ b/tests/Type/InlineKeyboardButtonTest.php @@ -25,6 +25,8 @@ public function testBase(): void $button = new InlineKeyboardButton('test'); assertSame('test', $button->text); + assertNull($button->iconCustomEmojiId); + assertNull($button->style); assertNull($button->url); assertNull($button->callbackData); assertNull($button->webApp); @@ -63,9 +65,13 @@ public function testFilled(): void $callbackGame, true, $copyText, + '5368324170671202286', + 'primary', ); assertSame('test', $button->text); + assertSame('5368324170671202286', $button->iconCustomEmojiId); + assertSame('primary', $button->style); assertSame('https://example.com', $button->url); assertSame('callback-data', $button->callbackData); assertSame($webApp, $button->webApp); @@ -80,6 +86,8 @@ public function testFilled(): void assertSame( [ 'text' => 'test', + 'icon_custom_emoji_id' => '5368324170671202286', + 'style' => 'primary', 'url' => 'https://example.com', 'callback_data' => 'callback-data', 'web_app' => $webApp->toRequestArray(), @@ -99,6 +107,8 @@ public function testFromTelegramResult(): void { $button = (new ObjectFactory())->create([ 'text' => 'test', + 'icon_custom_emoji_id' => '5368324170671202286', + 'style' => 'primary', 'url' => 'https://example.com', 'callback_data' => 'callback-data', 'web_app' => ['url' => 'https://example.com/test'], @@ -112,6 +122,8 @@ public function testFromTelegramResult(): void ], null, InlineKeyboardButton::class); assertSame('test', $button->text); + assertSame('5368324170671202286', $button->iconCustomEmojiId); + assertSame('primary', $button->style); assertSame('https://example.com', $button->url); assertSame('callback-data', $button->callbackData); assertSame('https://example.com/test', $button->webApp?->url); diff --git a/tests/Type/KeyboardButtonTest.php b/tests/Type/KeyboardButtonTest.php index 6cbb0b5b..a0404803 100644 --- a/tests/Type/KeyboardButtonTest.php +++ b/tests/Type/KeyboardButtonTest.php @@ -23,6 +23,8 @@ public function testBase(): void $button = new KeyboardButton('test'); assertSame('test', $button->text); + assertNull($button->iconCustomEmojiId); + assertNull($button->style); assertNull($button->requestUsers); assertNull($button->requestChat); assertNull($button->requestContact); @@ -52,9 +54,13 @@ public function testFilled(): void false, $requestPoll, $webApp, + '5368324170671202286', + 'primary', ); assertSame('test', $button->text); + assertSame('5368324170671202286', $button->iconCustomEmojiId); + assertSame('primary', $button->style); assertSame($requestUsers, $button->requestUsers); assertSame($requestChat, $button->requestChat); assertTrue($button->requestContact); @@ -65,6 +71,8 @@ public function testFilled(): void assertSame( [ 'text' => 'test', + 'icon_custom_emoji_id' => '5368324170671202286', + 'style' => 'primary', 'request_users' => $requestUsers->toRequestArray(), 'request_chat' => $requestChat->toRequestArray(), 'request_contact' => true, From 292879aa5c4517b0e1512cdfa8258f2af1be986c Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 9 Feb 2026 22:49:24 +0300 Subject: [PATCH 03/18] Add `ChatOwnerLeft` type --- CHANGELOG.md | 1 + src/Type/ChatOwnerLeft.php | 17 ++++++++++++ tests/Type/ChatOwnerLeftTest.php | 46 ++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 src/Type/ChatOwnerLeft.php create mode 100644 tests/Type/ChatOwnerLeftTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 8503d95f..3a20ddba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - New #186: Add `allowsUsersToCreateTopics` field to `User` type. - New #186: Add `iconCustomEmojiId` and `style` fields to `KeyboardButton` type. - New #186: Add `iconCustomEmojiId` and `style` fields to `InlineKeyboardButton` type. +- New #186: Add `ChatOwnerLeft` type. ## 0.14 February 7, 2026 diff --git a/src/Type/ChatOwnerLeft.php b/src/Type/ChatOwnerLeft.php new file mode 100644 index 00000000..8be4fcd2 --- /dev/null +++ b/src/Type/ChatOwnerLeft.php @@ -0,0 +1,17 @@ +newOwner); + } + + public function testFull(): void + { + $newOwner = new User(1, false, 'Sergei'); + $chatOwnerLeft = new ChatOwnerLeft($newOwner); + + assertSame($newOwner, $chatOwnerLeft->newOwner); + } + + public function testFromTelegramResult(): void + { + $chatOwnerLeft = (new ObjectFactory())->create([ + 'new_owner' => [ + 'id' => 1, + 'is_bot' => false, + 'first_name' => 'Sergei', + ], + ], null, ChatOwnerLeft::class); + + assertInstanceOf(User::class, $chatOwnerLeft->newOwner); + assertSame(1, $chatOwnerLeft->newOwner->id); + } +} From 3a6cc11a172e66a8b89c956d606079166a38d677 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 9 Feb 2026 22:54:41 +0300 Subject: [PATCH 04/18] Add `ChatOwnerChanged` type --- CHANGELOG.md | 2 +- src/Type/ChatOwnerChanged.php | 19 +++++++++++++++ tests/Type/ChatOwnerChangedTest.php | 38 +++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 src/Type/ChatOwnerChanged.php create mode 100644 tests/Type/ChatOwnerChangedTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a20ddba..000a1397 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ - New #186: Add `allowsUsersToCreateTopics` field to `User` type. - New #186: Add `iconCustomEmojiId` and `style` fields to `KeyboardButton` type. - New #186: Add `iconCustomEmojiId` and `style` fields to `InlineKeyboardButton` type. -- New #186: Add `ChatOwnerLeft` type. +- New #186: Add `ChatOwnerLeft` and `ChatOwnerChanged` types. ## 0.14 February 7, 2026 diff --git a/src/Type/ChatOwnerChanged.php b/src/Type/ChatOwnerChanged.php new file mode 100644 index 00000000..bc38e0b2 --- /dev/null +++ b/src/Type/ChatOwnerChanged.php @@ -0,0 +1,19 @@ +newOwner); + } + + public function testFromTelegramResult(): void + { + $chatOwnerChanged = (new ObjectFactory())->create([ + 'new_owner' => [ + 'id' => 1, + 'is_bot' => false, + 'first_name' => 'Sergei', + ], + ], null, ChatOwnerChanged::class); + + assertInstanceOf(User::class, $chatOwnerChanged->newOwner); + assertSame(1, $chatOwnerChanged->newOwner->id); + } +} From 19dd7dcbe5215b7b97755001f0427a0cdc72ed3f Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 9 Feb 2026 22:59:48 +0300 Subject: [PATCH 05/18] Add `chatOwnerLeft` and `chatOwnerChanged` fields to `Message` type --- CHANGELOG.md | 1 + src/Type/Message.php | 2 ++ tests/Type/MessageTest.php | 20 ++++++++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 000a1397..ed000bb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - New #186: Add `iconCustomEmojiId` and `style` fields to `KeyboardButton` type. - New #186: Add `iconCustomEmojiId` and `style` fields to `InlineKeyboardButton` type. - New #186: Add `ChatOwnerLeft` and `ChatOwnerChanged` types. +- New #186: Add `chatOwnerLeft` and `chatOwnerChanged` fields to `Message` type. ## 0.14 February 7, 2026 diff --git a/src/Type/Message.php b/src/Type/Message.php index 6d5cc080..3273a833 100644 --- a/src/Type/Message.php +++ b/src/Type/Message.php @@ -138,5 +138,7 @@ public function __construct( public ?SuggestedPostDeclined $suggestedPostDeclined = null, public ?SuggestedPostPaid $suggestedPostPaid = null, public ?SuggestedPostRefunded $suggestedPostRefunded = null, + public ?ChatOwnerLeft $chatOwnerLeft = null, + public ?ChatOwnerChanged $chatOwnerChanged = null, ) {} } diff --git a/tests/Type/MessageTest.php b/tests/Type/MessageTest.php index 12b984a1..ba0fbb76 100644 --- a/tests/Type/MessageTest.php +++ b/tests/Type/MessageTest.php @@ -11,6 +11,8 @@ use Phptg\BotApi\Type\Checklist; use Phptg\BotApi\Type\ChecklistTask; use Phptg\BotApi\Type\ChecklistTasksAdded; +use Phptg\BotApi\Type\ChatOwnerChanged; +use Phptg\BotApi\Type\ChatOwnerLeft; use Phptg\BotApi\Type\ChecklistTasksDone; use Phptg\BotApi\Type\DirectMessagePriceChanged; use Phptg\BotApi\Type\ExternalReplyInfo; @@ -143,6 +145,8 @@ public function testBase(): void assertNull($message->suggestedPostDeclined); assertNull($message->suggestedPostPaid); assertNull($message->suggestedPostRefunded); + assertNull($message->chatOwnerLeft); + assertNull($message->chatOwnerChanged); } public function testFromTelegramResult(): void @@ -633,6 +637,20 @@ public function testFromTelegramResult(): void ['id' => 4, 'text' => 'Task 4'], ], ], + 'chat_owner_left' => [ + 'new_owner' => [ + 'id' => 800, + 'is_bot' => false, + 'first_name' => 'Sergei', + ], + ], + 'chat_owner_changed' => [ + 'new_owner' => [ + 'id' => 801, + 'is_bot' => false, + 'first_name' => 'Ivan', + ], + ], ], null, Message::class); assertSame(7, $message->messageId); @@ -771,5 +789,7 @@ public function testFromTelegramResult(): void assertSame('insufficient_funds', $message->suggestedPostDeclined?->comment); assertSame('RUB', $message->suggestedPostPaid?->currency); assertSame('refund_reason', $message->suggestedPostRefunded?->reason); + assertSame(800, $message->chatOwnerLeft?->newOwner?->id); + assertSame(801, $message->chatOwnerChanged?->newOwner->id); } } From 712d2b747338055f92d71711edab98fd986f3170 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 9 Feb 2026 23:09:04 +0300 Subject: [PATCH 06/18] Add `SetMyProfilePhoto` method --- CHANGELOG.md | 1 + src/Method/SetMyProfilePhoto.php | 51 ++++++++++++++++++++++++++ src/TelegramBotApi.php | 9 +++++ tests/Method/SetMyProfilePhotoTest.php | 48 ++++++++++++++++++++++++ tests/TelegramBotApiTest.php | 13 +++++++ 5 files changed, 122 insertions(+) create mode 100644 src/Method/SetMyProfilePhoto.php create mode 100644 tests/Method/SetMyProfilePhotoTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index ed000bb9..ef9a1355 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - New #186: Add `iconCustomEmojiId` and `style` fields to `InlineKeyboardButton` type. - New #186: Add `ChatOwnerLeft` and `ChatOwnerChanged` types. - New #186: Add `chatOwnerLeft` and `chatOwnerChanged` fields to `Message` type. +- New #186: Add `SetMyProfilePhoto` method. ## 0.14 February 7, 2026 diff --git a/src/Method/SetMyProfilePhoto.php b/src/Method/SetMyProfilePhoto.php new file mode 100644 index 00000000..477b00d3 --- /dev/null +++ b/src/Method/SetMyProfilePhoto.php @@ -0,0 +1,51 @@ + + * + * @api + */ +final readonly class SetMyProfilePhoto implements MethodInterface +{ + public function __construct( + private InputProfilePhoto $photo, + ) {} + + public function getHttpMethod(): HttpMethod + { + return HttpMethod::POST; + } + + public function getApiMethod(): string + { + return 'setMyProfilePhoto'; + } + + public function getData(): array + { + $fileCollector = new FileCollector(); + $photo = $this->photo->toRequestArray($fileCollector); + + return [ + 'photo' => $photo, + ...$fileCollector->get(), + ]; + } + + public function getResultType(): TrueValue + { + return new TrueValue(); + } +} diff --git a/src/TelegramBotApi.php b/src/TelegramBotApi.php index 4023f102..430e1737 100644 --- a/src/TelegramBotApi.php +++ b/src/TelegramBotApi.php @@ -123,6 +123,7 @@ use Phptg\BotApi\Method\SetMyDefaultAdministratorRights; use Phptg\BotApi\Method\SetMyDescription; use Phptg\BotApi\Method\SetMyName; +use Phptg\BotApi\Method\SetMyProfilePhoto; use Phptg\BotApi\Method\SetMyShortDescription; use Phptg\BotApi\Method\SetUserEmojiStatus; use Phptg\BotApi\Method\Sticker\AddStickerToSet; @@ -2956,6 +2957,14 @@ public function setMyName(?string $name = null, ?string $languageCode = null): F return $this->call(new SetMyName($name, $languageCode)); } + /** + * @see https://core.telegram.org/bots/api#setmyprofilephoto + */ + public function setMyProfilePhoto(InputProfilePhoto $photo): FailResult|true + { + return $this->call(new SetMyProfilePhoto($photo)); + } + /** * @see https://core.telegram.org/bots/api#setmyshortdescription */ diff --git a/tests/Method/SetMyProfilePhotoTest.php b/tests/Method/SetMyProfilePhotoTest.php new file mode 100644 index 00000000..17f7197d --- /dev/null +++ b/tests/Method/SetMyProfilePhotoTest.php @@ -0,0 +1,48 @@ +createStream()); + $photo = new InputProfilePhotoStatic($file); + $method = new SetMyProfilePhoto($photo); + + assertSame(HttpMethod::POST, $method->getHttpMethod()); + assertSame('setMyProfilePhoto', $method->getApiMethod()); + assertSame( + [ + 'photo' => $photo->toRequestArray(new FileCollector()), + 'file0' => $file, + ], + $method->getData(), + ); + } + + public function testPrepareResult(): void + { + $file = new InputFile((new StreamFactory())->createStream()); + $photo = new InputProfilePhotoStatic($file); + $method = new SetMyProfilePhoto($photo); + + $preparedResult = TestHelper::createSuccessStubApi(true)->call($method); + + assertTrue($preparedResult); + } +} diff --git a/tests/TelegramBotApiTest.php b/tests/TelegramBotApiTest.php index c24324eb..cf50b8c4 100644 --- a/tests/TelegramBotApiTest.php +++ b/tests/TelegramBotApiTest.php @@ -2312,6 +2312,19 @@ public function testSetMyName(): void assertTrue($result); } + public function testSetMyProfilePhoto(): void + { + $api = TestHelper::createSuccessStubApi(true); + + $result = $api->setMyProfilePhoto( + new InputProfilePhotoStatic( + new InputFile((new StreamFactory())->createStream()), + ), + ); + + assertTrue($result); + } + public function testSetMyShortDescription(): void { $api = TestHelper::createSuccessStubApi(true); From 1f36ce024691e90cf739ad9cc61e247074b872f3 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 9 Feb 2026 23:13:17 +0300 Subject: [PATCH 07/18] Add `RemoveMyProfilePhoto` method --- CHANGELOG.md | 1 + src/Method/RemoveMyProfilePhoto.php | 39 +++++++++++++++++++++++ src/TelegramBotApi.php | 9 ++++++ tests/Method/RemoveMyProfilePhotoTest.php | 34 ++++++++++++++++++++ tests/TelegramBotApiTest.php | 9 ++++++ 5 files changed, 92 insertions(+) create mode 100644 src/Method/RemoveMyProfilePhoto.php create mode 100644 tests/Method/RemoveMyProfilePhotoTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index ef9a1355..054dd511 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - New #186: Add `ChatOwnerLeft` and `ChatOwnerChanged` types. - New #186: Add `chatOwnerLeft` and `chatOwnerChanged` fields to `Message` type. - New #186: Add `SetMyProfilePhoto` method. +- New #186: Add `RemoveMyProfilePhoto` method. ## 0.14 February 7, 2026 diff --git a/src/Method/RemoveMyProfilePhoto.php b/src/Method/RemoveMyProfilePhoto.php new file mode 100644 index 00000000..95afed2e --- /dev/null +++ b/src/Method/RemoveMyProfilePhoto.php @@ -0,0 +1,39 @@ + + * + * @api + */ +final readonly class RemoveMyProfilePhoto implements MethodInterface +{ + public function getHttpMethod(): HttpMethod + { + return HttpMethod::POST; + } + + public function getApiMethod(): string + { + return 'removeMyProfilePhoto'; + } + + public function getData(): array + { + return []; + } + + public function getResultType(): TrueValue + { + return new TrueValue(); + } +} diff --git a/src/TelegramBotApi.php b/src/TelegramBotApi.php index 430e1737..c7bd8cea 100644 --- a/src/TelegramBotApi.php +++ b/src/TelegramBotApi.php @@ -82,6 +82,7 @@ use Phptg\BotApi\Method\PromoteChatMember; use Phptg\BotApi\Method\RepostStory; use Phptg\BotApi\Method\RemoveBusinessAccountProfilePhoto; +use Phptg\BotApi\Method\RemoveMyProfilePhoto; use Phptg\BotApi\Method\RemoveChatVerification; use Phptg\BotApi\Method\RemoveUserVerification; use Phptg\BotApi\Method\ReopenForumTopic; @@ -1684,6 +1685,14 @@ public function removeBusinessAccountProfilePhoto( ); } + /** + * @see https://core.telegram.org/bots/api#removemyprofilephoto + */ + public function removeMyProfilePhoto(): FailResult|true + { + return $this->call(new RemoveMyProfilePhoto()); + } + /** * @see https://core.telegram.org/bots/api#removechatverification */ diff --git a/tests/Method/RemoveMyProfilePhotoTest.php b/tests/Method/RemoveMyProfilePhotoTest.php new file mode 100644 index 00000000..9063522a --- /dev/null +++ b/tests/Method/RemoveMyProfilePhotoTest.php @@ -0,0 +1,34 @@ +getHttpMethod()); + assertSame('removeMyProfilePhoto', $method->getApiMethod()); + assertSame([], $method->getData()); + } + + public function testPrepareResult(): void + { + $method = new RemoveMyProfilePhoto(); + + $preparedResult = TestHelper::createSuccessStubApi(true)->call($method); + + assertTrue($preparedResult); + } +} diff --git a/tests/TelegramBotApiTest.php b/tests/TelegramBotApiTest.php index cf50b8c4..6aeb9744 100644 --- a/tests/TelegramBotApiTest.php +++ b/tests/TelegramBotApiTest.php @@ -1676,6 +1676,15 @@ public function testRemoveBusinessAccountProfilePhoto(): void assertTrue($result); } + public function testRemoveMyProfilePhoto(): void + { + $api = TestHelper::createSuccessStubApi(true); + + $result = $api->removeMyProfilePhoto(); + + assertTrue($result); + } + public function testRemoveChatVerification(): void { $api = TestHelper::createSuccessStubApi(true); From eaec9282744c555e332bf73d8799ee5f14dec453 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 9 Feb 2026 23:18:31 +0300 Subject: [PATCH 08/18] Add `VideoQuality` type --- CHANGELOG.md | 1 + src/Type/VideoQuality.php | 22 ++++++++++++ tests/Type/VideoQualityTest.php | 60 +++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 src/Type/VideoQuality.php create mode 100644 tests/Type/VideoQualityTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 054dd511..cc107352 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - New #186: Add `chatOwnerLeft` and `chatOwnerChanged` fields to `Message` type. - New #186: Add `SetMyProfilePhoto` method. - New #186: Add `RemoveMyProfilePhoto` method. +- New #186: Add `VideoQuality` type. ## 0.14 February 7, 2026 diff --git a/src/Type/VideoQuality.php b/src/Type/VideoQuality.php new file mode 100644 index 00000000..12be820c --- /dev/null +++ b/src/Type/VideoQuality.php @@ -0,0 +1,22 @@ +fileId); + assertSame('fileUniqueId', $videoQuality->fileUniqueId); + assertSame(1920, $videoQuality->width); + assertSame(1080, $videoQuality->height); + assertSame('h264', $videoQuality->codec); + assertNull($videoQuality->fileSize); + } + + public function testFull(): void + { + $videoQuality = new VideoQuality('fileId', 'fileUniqueId', 1920, 1080, 'h265', 4096); + + assertSame('fileId', $videoQuality->fileId); + assertSame('fileUniqueId', $videoQuality->fileUniqueId); + assertSame(1920, $videoQuality->width); + assertSame(1080, $videoQuality->height); + assertSame('h265', $videoQuality->codec); + assertSame(4096, $videoQuality->fileSize); + } + + public function testFromTelegramResult(): void + { + $videoQuality = (new ObjectFactory())->create([ + 'file_id' => 'fileId', + 'file_unique_id' => 'fileUniqueId', + 'width' => 1920, + 'height' => 1080, + 'codec' => 'h265', + 'file_size' => 4096, + ], null, VideoQuality::class); + + assertInstanceOf(VideoQuality::class, $videoQuality); + assertSame('fileId', $videoQuality->fileId); + assertSame('fileUniqueId', $videoQuality->fileUniqueId); + assertSame(1920, $videoQuality->width); + assertSame(1080, $videoQuality->height); + assertSame('h265', $videoQuality->codec); + assertSame(4096, $videoQuality->fileSize); + } +} From b6135d11facf34b153eba414cb3cb5181da544c3 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 9 Feb 2026 23:21:26 +0300 Subject: [PATCH 09/18] Add `qualities` field to `Video` type --- CHANGELOG.md | 1 + src/Type/Video.php | 3 +++ tests/Type/VideoTest.php | 21 +++++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc107352..6d53b36b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - New #186: Add `SetMyProfilePhoto` method. - New #186: Add `RemoveMyProfilePhoto` method. - New #186: Add `VideoQuality` type. +- New #186: Add `qualities` field to `Video` type. ## 0.14 February 7, 2026 diff --git a/src/Type/Video.php b/src/Type/Video.php index 6f2234bd..a9777731 100644 --- a/src/Type/Video.php +++ b/src/Type/Video.php @@ -15,6 +15,7 @@ { /** * @param PhotoSize[]|null $cover + * @param VideoQuality[]|null $qualities */ public function __construct( public string $fileId, @@ -29,5 +30,7 @@ public function __construct( #[ArrayOfObjectsValue(PhotoSize::class)] public ?array $cover = null, public ?int $startTimestamp = null, + #[ArrayOfObjectsValue(VideoQuality::class)] + public ?array $qualities = null, ) {} } diff --git a/tests/Type/VideoTest.php b/tests/Type/VideoTest.php index 45eb27f6..b008c6dd 100644 --- a/tests/Type/VideoTest.php +++ b/tests/Type/VideoTest.php @@ -29,6 +29,7 @@ public function testBase(): void assertNull($video->fileSize); assertNull($video->cover); assertNull($video->startTimestamp); + assertNull($video->qualities); } public function testFromTelegramResult(): void @@ -60,6 +61,23 @@ public function testFromTelegramResult(): void ], ], 'start_timestamp' => 17, + 'qualities' => [ + [ + 'file_id' => 'fq1', + 'file_unique_id' => 'fuq1', + 'width' => 1920, + 'height' => 1080, + 'codec' => 'h264', + 'file_size' => 50000, + ], + [ + 'file_id' => 'fq2', + 'file_unique_id' => 'fuq2', + 'width' => 1280, + 'height' => 720, + 'codec' => 'h265', + ], + ], 'file_name' => 'face.png', 'mime_type' => 'image/png', 'file_size' => 123, @@ -78,5 +96,8 @@ public function testFromTelegramResult(): void assertSame('file_id-3', $video->cover[0]->fileId); assertSame('file_id-4', $video->cover[1]->fileId); assertSame(17, $video->startTimestamp); + assertCount(2, $video->qualities); + assertSame('fq1', $video->qualities[0]->fileId); + assertSame('fq2', $video->qualities[1]->fileId); } } From b06f4c835421993ee5e29a0fa84db24642da01b7 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 9 Feb 2026 23:25:29 +0300 Subject: [PATCH 10/18] Add `firstProfileAudio` field to `ChatFullInfo` type --- CHANGELOG.md | 1 + src/Type/ChatFullInfo.php | 1 + tests/Type/ChatFullInfoTest.php | 15 +++++++++++++++ 3 files changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d53b36b..7e6cd73f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - New #186: Add `RemoveMyProfilePhoto` method. - New #186: Add `VideoQuality` type. - New #186: Add `qualities` field to `Video` type. +- New #186: Add `firstProfileAudio` field to `ChatFullInfo` type. ## 0.14 February 7, 2026 diff --git a/src/Type/ChatFullInfo.php b/src/Type/ChatFullInfo.php index 8d1af0b1..a1bf69d8 100644 --- a/src/Type/ChatFullInfo.php +++ b/src/Type/ChatFullInfo.php @@ -73,5 +73,6 @@ public function __construct( public ?UserRating $rating = null, public ?UniqueGiftColors $uniqueGiftColors = null, public ?int $paidMessageStarCount = null, + public ?Audio $firstProfileAudio = null, ) {} } diff --git a/tests/Type/ChatFullInfoTest.php b/tests/Type/ChatFullInfoTest.php index 9e2403c2..f5c5f8f4 100644 --- a/tests/Type/ChatFullInfoTest.php +++ b/tests/Type/ChatFullInfoTest.php @@ -18,6 +18,7 @@ use Phptg\BotApi\Type\ChatPhoto; use Phptg\BotApi\Type\Message; use Phptg\BotApi\Type\ReactionTypeCustomEmoji; +use Phptg\BotApi\Type\Audio; use Phptg\BotApi\Type\UniqueGiftColors; use Phptg\BotApi\Type\UserRating; @@ -85,6 +86,7 @@ public function testBase(): void assertNull($info->rating); assertNull($info->uniqueGiftColors); assertNull($info->paidMessageStarCount); + assertNull($info->firstProfileAudio); } public function testFromTelegramResult(): void @@ -195,6 +197,13 @@ public function testFromTelegramResult(): void 'current_level_rating' => 800, 'next_level_rating' => 1200, ], + 'first_profile_audio' => [ + 'file_id' => 'audio_f1', + 'file_unique_id' => 'audio_fu1', + 'duration' => 180, + 'performer' => 'Artist', + 'title' => 'Song', + ], 'unique_gift_colors' => [ 'model_custom_emoji_id' => 'model_emoji_123', 'symbol_custom_emoji_id' => 'symbol_emoji_456', @@ -299,5 +308,11 @@ public function testFromTelegramResult(): void assertSame([0x2A2A2A, 0x3A3A3A], $info->uniqueGiftColors->darkThemeOtherColors); assertSame(100, $info->paidMessageStarCount); + + assertInstanceOf(Audio::class, $info->firstProfileAudio); + assertSame('audio_f1', $info->firstProfileAudio->fileId); + assertSame(180, $info->firstProfileAudio->duration); + assertSame('Artist', $info->firstProfileAudio->performer); + assertSame('Song', $info->firstProfileAudio->title); } } From c2817fdbbbe9476e19c52f8c30a727ac06d87f3d Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 9 Feb 2026 23:28:20 +0300 Subject: [PATCH 11/18] Add `UserProfileAudios` type --- CHANGELOG.md | 1 + src/Type/UserProfileAudios.php | 24 +++++++++++++ tests/Type/UserProfileAudiosTest.php | 51 ++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 src/Type/UserProfileAudios.php create mode 100644 tests/Type/UserProfileAudiosTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e6cd73f..1bfff14c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - New #186: Add `VideoQuality` type. - New #186: Add `qualities` field to `Video` type. - New #186: Add `firstProfileAudio` field to `ChatFullInfo` type. +- New #186: Add `UserProfileAudios` type. ## 0.14 February 7, 2026 diff --git a/src/Type/UserProfileAudios.php b/src/Type/UserProfileAudios.php new file mode 100644 index 00000000..5c39c5ef --- /dev/null +++ b/src/Type/UserProfileAudios.php @@ -0,0 +1,24 @@ +totalCount); + assertSame([], $userProfileAudios->audios); + } + + public function testFromTelegramResult(): void + { + $userProfileAudios = (new ObjectFactory())->create([ + 'total_count' => 2, + 'audios' => [ + [ + 'file_id' => 'audio_f1', + 'file_unique_id' => 'audio_fu1', + 'duration' => 180, + 'performer' => 'Artist 1', + 'title' => 'Song 1', + ], + [ + 'file_id' => 'audio_f2', + 'file_unique_id' => 'audio_fu2', + 'duration' => 240, + 'performer' => 'Artist 2', + 'title' => 'Song 2', + ], + ], + ], null, UserProfileAudios::class); + + assertSame(2, $userProfileAudios->totalCount); + assertCount(2, $userProfileAudios->audios); + assertSame('audio_f1', $userProfileAudios->audios[0]->fileId); + assertSame('audio_f2', $userProfileAudios->audios[1]->fileId); + } +} From 5ecbb3e4013950ceef8ead595908ccfb98ee55a9 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 9 Feb 2026 23:33:11 +0300 Subject: [PATCH 12/18] Add `GetUserProfileAudios` method --- CHANGELOG.md | 1 + src/Method/GetUserProfileAudios.php | 51 +++++++++++++++++ src/TelegramBotApi.php | 15 +++++ tests/Method/GetUserProfileAudiosTest.php | 70 +++++++++++++++++++++++ tests/TelegramBotApiTest.php | 13 +++++ 5 files changed, 150 insertions(+) create mode 100644 src/Method/GetUserProfileAudios.php create mode 100644 tests/Method/GetUserProfileAudiosTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bfff14c..7ab77aa5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - New #186: Add `qualities` field to `Video` type. - New #186: Add `firstProfileAudio` field to `ChatFullInfo` type. - New #186: Add `UserProfileAudios` type. +- New #186: Add `GetUserProfileAudios` method. ## 0.14 February 7, 2026 diff --git a/src/Method/GetUserProfileAudios.php b/src/Method/GetUserProfileAudios.php new file mode 100644 index 00000000..b84b0e1e --- /dev/null +++ b/src/Method/GetUserProfileAudios.php @@ -0,0 +1,51 @@ + + */ +final readonly class GetUserProfileAudios implements MethodInterface +{ + public function __construct( + private int $userId, + private ?int $offset = null, + private ?int $limit = null, + ) {} + + public function getHttpMethod(): HttpMethod + { + return HttpMethod::GET; + } + + public function getApiMethod(): string + { + return 'getUserProfileAudios'; + } + + public function getData(): array + { + return array_filter( + [ + 'user_id' => $this->userId, + 'offset' => $this->offset, + 'limit' => $this->limit, + ], + static fn(mixed $value): bool => $value !== null, + ); + } + + public function getResultType(): ObjectValue + { + return new ObjectValue(UserProfileAudios::class); + } +} diff --git a/src/TelegramBotApi.php b/src/TelegramBotApi.php index c7bd8cea..2ebac77d 100644 --- a/src/TelegramBotApi.php +++ b/src/TelegramBotApi.php @@ -61,6 +61,7 @@ use Phptg\BotApi\Method\GetMyStarBalance; use Phptg\BotApi\Method\GetUserChatBoosts; use Phptg\BotApi\Method\GetUserGifts; +use Phptg\BotApi\Method\GetUserProfileAudios; use Phptg\BotApi\Method\GetUserProfilePhotos; use Phptg\BotApi\Method\GiftPremiumSubscription; use Phptg\BotApi\Method\HideGeneralForumTopic; @@ -238,6 +239,7 @@ use Phptg\BotApi\Type\Update\WebhookInfo; use Phptg\BotApi\Type\User; use Phptg\BotApi\Type\UserChatBoosts; +use Phptg\BotApi\Type\UserProfileAudios; use Phptg\BotApi\Type\UserProfilePhotos; use function extension_loaded; @@ -1461,6 +1463,19 @@ public function getUserGifts( ); } + /** + * @see https://core.telegram.org/bots/api#getuserprofileaudios + */ + public function getUserProfileAudios( + int $userId, + ?int $offset = null, + ?int $limit = null, + ): FailResult|UserProfileAudios { + return $this->call( + new GetUserProfileAudios($userId, $offset, $limit), + ); + } + /** * @see https://core.telegram.org/bots/api#getuserprofilephotos */ diff --git a/tests/Method/GetUserProfileAudiosTest.php b/tests/Method/GetUserProfileAudiosTest.php new file mode 100644 index 00000000..27502064 --- /dev/null +++ b/tests/Method/GetUserProfileAudiosTest.php @@ -0,0 +1,70 @@ +getHttpMethod()); + assertSame('getUserProfileAudios', $method->getApiMethod()); + assertSame( + [ + 'user_id' => 123, + ], + $method->getData(), + ); + } + + public function testFull(): void + { + $method = new GetUserProfileAudios( + 123, + 1, + 2, + ); + + assertSame( + [ + 'user_id' => 123, + 'offset' => 1, + 'limit' => 2, + ], + $method->getData(), + ); + } + + public function testPrepareResult(): void + { + $method = new GetUserProfileAudios(123); + + $preparedResult = TestHelper::createSuccessStubApi([ + 'total_count' => 1, + 'audios' => [ + [ + 'file_id' => 'file_id', + 'file_unique_id' => 'file_unique_id', + 'duration' => 120, + 'performer' => 'performer', + 'title' => 'title', + ], + ], + ])->call($method); + + assertSame(1, $preparedResult->totalCount); + assertCount(1, $preparedResult->audios); + assertSame('file_id', $preparedResult->audios[0]->fileId); + } +} diff --git a/tests/TelegramBotApiTest.php b/tests/TelegramBotApiTest.php index 6aeb9744..88f0cdaa 100644 --- a/tests/TelegramBotApiTest.php +++ b/tests/TelegramBotApiTest.php @@ -53,6 +53,7 @@ use Phptg\BotApi\Type\Story; use Phptg\BotApi\Type\User; use Phptg\BotApi\Type\UserChatBoosts; +use Phptg\BotApi\Type\UserProfileAudios; use Phptg\BotApi\Type\UserProfilePhotos; use Phptg\BotApi\Type\Update\Update; use Phptg\BotApi\Type\Update\WebhookInfo; @@ -1518,6 +1519,18 @@ public function testGetUserGifts(): void assertInstanceOf(OwnedGifts::class, $result); } + public function testGetUserProfileAudios(): void + { + $api = TestHelper::createSuccessStubApi([ + 'total_count' => 0, + 'audios' => [], + ]); + + $result = $api->getUserProfileAudios(7); + + assertInstanceOf(UserProfileAudios::class, $result); + } + public function testGetUserProfilePhotos(): void { $api = TestHelper::createSuccessStubApi([ From cdda4e4cc511746f5a2b71acd6b50001e943bf50 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 9 Feb 2026 23:36:09 +0300 Subject: [PATCH 13/18] Add `rarity` field to `UniqueGiftModel` type --- CHANGELOG.md | 1 + src/Type/UniqueGiftModel.php | 1 + tests/Type/UniqueGiftModelTest.php | 15 +++++++++++++++ 3 files changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ab77aa5..5e9fedda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - New #186: Add `firstProfileAudio` field to `ChatFullInfo` type. - New #186: Add `UserProfileAudios` type. - New #186: Add `GetUserProfileAudios` method. +- New #186: Add `rarity` field to `UniqueGiftModel` type. ## 0.14 February 7, 2026 diff --git a/src/Type/UniqueGiftModel.php b/src/Type/UniqueGiftModel.php index 28cef407..21ece9dd 100644 --- a/src/Type/UniqueGiftModel.php +++ b/src/Type/UniqueGiftModel.php @@ -17,5 +17,6 @@ public function __construct( public string $name, public Sticker $sticker, public int $rarityPerMille, + public ?string $rarity = null, ) {} } diff --git a/tests/Type/UniqueGiftModelTest.php b/tests/Type/UniqueGiftModelTest.php index 004731d4..0d34e90a 100644 --- a/tests/Type/UniqueGiftModelTest.php +++ b/tests/Type/UniqueGiftModelTest.php @@ -10,6 +10,7 @@ use Phptg\BotApi\Type\UniqueGiftModel; use function PHPUnit\Framework\assertInstanceOf; +use function PHPUnit\Framework\assertNull; use function PHPUnit\Framework\assertSame; final class UniqueGiftModelTest extends TestCase @@ -22,6 +23,18 @@ public function testBase(): void assertSame('modelId', $model->name); assertSame($sticker, $model->sticker); assertSame(500, $model->rarityPerMille); + assertNull($model->rarity); + } + + public function testFull(): void + { + $sticker = new Sticker('stickerId', 'uniqueStickerId', 'unique', 100, 120, false, true); + $model = new UniqueGiftModel('modelId', $sticker, 500, 'rare'); + + assertSame('modelId', $model->name); + assertSame($sticker, $model->sticker); + assertSame(500, $model->rarityPerMille); + assertSame('rare', $model->rarity); } public function testFromTelegramResult(): void @@ -38,11 +51,13 @@ public function testFromTelegramResult(): void 'is_video' => true, ], 'rarity_per_mille' => 500, + 'rarity' => 'epic', ], null, UniqueGiftModel::class); assertInstanceOf(UniqueGiftModel::class, $model); assertSame('modelId', $model->name); assertSame('stickerId', $model->sticker->fileId); assertSame(500, $model->rarityPerMille); + assertSame('epic', $model->rarity); } } From 996ae862dedf67dbb77aa3349873ee7630e91ef2 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 9 Feb 2026 23:37:47 +0300 Subject: [PATCH 14/18] Add `isBurned` field to `UniqueGift` type --- CHANGELOG.md | 1 + src/Type/UniqueGift.php | 1 + tests/Type/UniqueGiftTest.php | 60 +++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e9fedda..1b33bd18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - New #186: Add `UserProfileAudios` type. - New #186: Add `GetUserProfileAudios` method. - New #186: Add `rarity` field to `UniqueGiftModel` type. +- New #186: Add `isBurned` field to `UniqueGift` type. ## 0.14 February 7, 2026 diff --git a/src/Type/UniqueGift.php b/src/Type/UniqueGift.php index e78ce96c..def6df2f 100644 --- a/src/Type/UniqueGift.php +++ b/src/Type/UniqueGift.php @@ -23,5 +23,6 @@ public function __construct( public ?true $isFromBlockchain = null, public ?UniqueGiftColors $colors = null, public ?Chat $publisherChat = null, + public ?true $isBurned = null, ) {} } diff --git a/tests/Type/UniqueGiftTest.php b/tests/Type/UniqueGiftTest.php index b10aa47a..958205d6 100644 --- a/tests/Type/UniqueGiftTest.php +++ b/tests/Type/UniqueGiftTest.php @@ -6,6 +6,7 @@ use PHPUnit\Framework\TestCase; use Phptg\BotApi\ParseResult\ObjectFactory; +use Phptg\BotApi\Type\Chat; use Phptg\BotApi\Type\Sticker\Sticker; use Phptg\BotApi\Type\UniqueGift; use Phptg\BotApi\Type\UniqueGiftBackdrop; @@ -51,6 +52,63 @@ public function testBase(): void assertNull($type->isFromBlockchain); assertNull($type->colors); assertNull($type->publisherChat); + assertNull($type->isBurned); + } + + public function testFull(): void + { + $model = new UniqueGiftModel( + 'modelId', + new Sticker('stickerId', 'uniqueStickerId', 'unique', 100, 120, false, true), + 500, + ); + $symbol = new UniqueGiftSymbol( + 'symbolId', + new Sticker('stickerId', 'uniqueStickerId', 'unique', 100, 120, false, true), + 300, + ); + $backdrop = new UniqueGiftBackdrop( + 'backdropId', + new UniqueGiftBackdropColors(1, 2, 3, 4), + 200, + ); + $colors = new UniqueGiftColors( + 'model-emoji-123', + 'symbol-emoji-456', + 16733525, + [13041721, 9473087], + 5773381, + [16761600, 14349222], + ); + $publisherChat = new Chat(789, 'channel'); + + $type = new UniqueGift( + 'gift123', + 'baseName', + 'uniqueName', + 1, + $model, + $symbol, + $backdrop, + true, + true, + $colors, + $publisherChat, + true, + ); + + assertSame('gift123', $type->giftId); + assertSame('baseName', $type->baseName); + assertSame('uniqueName', $type->name); + assertSame(1, $type->number); + assertSame($model, $type->model); + assertSame($symbol, $type->symbol); + assertSame($backdrop, $type->backdrop); + assertSame(true, $type->isPremium); + assertSame(true, $type->isFromBlockchain); + assertSame($colors, $type->colors); + assertSame($publisherChat, $type->publisherChat); + assertSame(true, $type->isBurned); } public function testFromTelegramResult(): void @@ -97,6 +155,7 @@ public function testFromTelegramResult(): void 'rarity_per_mille' => 200, ], 'is_premium' => true, + 'is_burned' => true, 'is_from_blockchain' => true, 'colors' => [ 'model_custom_emoji_id' => 'model-emoji-123', @@ -136,5 +195,6 @@ public function testFromTelegramResult(): void assertSame('symbol-emoji-456', $type->colors->symbolCustomEmojiId); assertSame(16733525, $type->colors->lightThemeMainColor); assertSame(789, $type->publisherChat?->id); + assertSame(true, $type->isBurned); } } From d06fa35898cb853182fe6859834ef3d32e08f59d Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 9 Feb 2026 23:39:57 +0300 Subject: [PATCH 15/18] readme + changelog --- CHANGELOG.md | 8 ++------ README.md | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b33bd18..281c5c0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,18 +2,14 @@ ## 0.14.1 under development +- New #186: Add `SetMyProfilePhoto`, `RemoveMyProfilePhoto` and `GetUserProfileAudios` methods. +- New #186: Add `ChatOwnerLeft`, `ChatOwnerChanged`, `VideoQuality` and `UserProfileAudios` types. - New #186: Add `allowsUsersToCreateTopics` field to `User` type. - New #186: Add `iconCustomEmojiId` and `style` fields to `KeyboardButton` type. - New #186: Add `iconCustomEmojiId` and `style` fields to `InlineKeyboardButton` type. -- New #186: Add `ChatOwnerLeft` and `ChatOwnerChanged` types. - New #186: Add `chatOwnerLeft` and `chatOwnerChanged` fields to `Message` type. -- New #186: Add `SetMyProfilePhoto` method. -- New #186: Add `RemoveMyProfilePhoto` method. -- New #186: Add `VideoQuality` type. - New #186: Add `qualities` field to `Video` type. - New #186: Add `firstProfileAudio` field to `ChatFullInfo` type. -- New #186: Add `UserProfileAudios` type. -- New #186: Add `GetUserProfileAudios` method. - New #186: Add `rarity` field to `UniqueGiftModel` type. - New #186: Add `isBurned` field to `UniqueGift` type. diff --git a/README.md b/README.md index b2e10e60..0c87c786 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.3 (December 31, 2025) is **fully supported**. +✔️ Telegram Bot API 9.4 (February 9, 2026) is **fully supported**. > [!IMPORTANT] > This project is developed and maintained by [Sergei Predvoditelev](https://github.com/vjik). From 20ab84ce416a94f00d0cc7c626f9d3b7c0099969 Mon Sep 17 00:00:00 2001 From: vjik <525501+vjik@users.noreply.github.com> Date: Mon, 9 Feb 2026 20:41:26 +0000 Subject: [PATCH 16/18] Apply PHP CS Fixer and Rector changes (CI) --- tests/Type/MessageTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Type/MessageTest.php b/tests/Type/MessageTest.php index ba0fbb76..cd0ab88e 100644 --- a/tests/Type/MessageTest.php +++ b/tests/Type/MessageTest.php @@ -11,8 +11,6 @@ use Phptg\BotApi\Type\Checklist; use Phptg\BotApi\Type\ChecklistTask; use Phptg\BotApi\Type\ChecklistTasksAdded; -use Phptg\BotApi\Type\ChatOwnerChanged; -use Phptg\BotApi\Type\ChatOwnerLeft; use Phptg\BotApi\Type\ChecklistTasksDone; use Phptg\BotApi\Type\DirectMessagePriceChanged; use Phptg\BotApi\Type\ExternalReplyInfo; From 5724efcb3eedc6d4141c6aa640b478f90d0473f0 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 9 Feb 2026 23:42:54 +0300 Subject: [PATCH 17/18] fix --- src/Type/ChatOwnerChanged.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Type/ChatOwnerChanged.php b/src/Type/ChatOwnerChanged.php index bc38e0b2..afcc134e 100644 --- a/src/Type/ChatOwnerChanged.php +++ b/src/Type/ChatOwnerChanged.php @@ -7,8 +7,6 @@ /** * @see https://core.telegram.org/bots/api#chatownerchanged * - * Describes a service message about an ownership change in the chat. - * * @api */ final readonly class ChatOwnerChanged From 4c73968ecf1dc33493f173e829be690692063b50 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 9 Feb 2026 23:46:16 +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 281c5c0f..353f8e8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Telegram Bot API for PHP Change Log -## 0.14.1 under development +## 0.14.1 February 9, 2026 - New #186: Add `SetMyProfilePhoto`, `RemoveMyProfilePhoto` and `GetUserProfileAudios` methods. - New #186: Add `ChatOwnerLeft`, `ChatOwnerChanged`, `VideoQuality` and `UserProfileAudios` types.