diff --git a/src/TgBotLib/Enums/Methods.php b/src/TgBotLib/Enums/Methods.php index f3f48be..3620d33 100644 --- a/src/TgBotLib/Enums/Methods.php +++ b/src/TgBotLib/Enums/Methods.php @@ -18,6 +18,7 @@ use TgBotLib\Methods\SendMessage; use TgBotLib\Methods\SendPhoto; use TgBotLib\Methods\SendVideo; + use TgBotLib\Methods\SendVoice; enum Methods : string { @@ -34,6 +35,7 @@ case SEND_DOCUMENT = 'sendDocument'; case SEND_VIDEO = 'sendVideo'; case SEND_ANIMATION = 'sendAnimation'; + case SEND_VOICE = 'sendVoice'; /** * Executes a command on the provided bot with the given parameters. @@ -60,6 +62,7 @@ self::SEND_DOCUMENT => SendDocument::execute($bot, $parameters), self::SEND_VIDEO => SendVideo::execute($bot, $parameters), self::SEND_ANIMATION => SendAnimation::execute($bot, $parameters), + self::SEND_VOICE => SendVoice::execute($bot, $parameters), }; } } diff --git a/src/TgBotLib/Methods/SendVoice.php b/src/TgBotLib/Methods/SendVoice.php new file mode 100644 index 0000000..57c8e9d --- /dev/null +++ b/src/TgBotLib/Methods/SendVoice.php @@ -0,0 +1,110 @@ +toArray(); + } + else + { + $entities[] = $entity; + } + } + $parameters['caption_entities'] = $entities; + } + + if (isset($parameters['reply_parameters']) && $parameters['reply_parameters'] instanceof ReplyParameters) + { + $parameters['reply_parameters'] = $parameters['reply_parameters']->toArray(); + } + + if (isset($parameters['reply_markup'])) + { + if ($parameters['reply_markup'] instanceof ObjectTypeInterface) + { + $parameters['reply_markup'] = json_encode($parameters['reply_markup']->toArray()); + } + elseif (is_array($parameters['reply_markup'])) + { + $parameters['reply_markup'] = json_encode($parameters['reply_markup']); + } + } + + // Handle different voice input types + if (isset($parameters['voice'])) + { + $voice = $parameters['voice']; + + // If voice is a file path and exists locally + if (is_string($voice) && file_exists($voice) && is_file($voice)) + { + return Message::fromArray(self::executeCurl(self::buildUpload($bot, Methods::SEND_VOICE->value, 'voice', $voice, array_diff_key($parameters, ['voice' => null])))); + } + } + + // If voice is a file_id or URL, use regular POST method + return Message::fromArray(self::executeCurl(self::buildPost($bot, Methods::SEND_VOICE->value, $parameters))); + } + + /** + * @inheritDoc + */ + public static function getRequiredParameters(): ?array + { + return [ + 'chat_id', + 'voice', + ]; + } + + /** + * @inheritDoc + */ + public static function getOptionalParameters(): ?array + { + return [ + 'business_connection_id', + 'message_thread_id', + 'caption', + 'parse_mode', + 'caption_entities', + 'duration', + 'disable_notification', + 'protect_content', + 'message_effect_id', + 'reply_parameters', + 'reply_markup' + ]; + } + } diff --git a/tests/TgBotLib/Methods/SendVoiceTest.php b/tests/TgBotLib/Methods/SendVoiceTest.php new file mode 100644 index 0000000..5fef1b4 --- /dev/null +++ b/tests/TgBotLib/Methods/SendVoiceTest.php @@ -0,0 +1,120 @@ +sendVoice( + chat_id: TEST_CHAT_ID, + voice: __DIR__ . DIRECTORY_SEPARATOR . 'sample' . DIRECTORY_SEPARATOR . 'ted.ogg', + caption: 'Test Unit: testSendVoice', + duration: 30, + disable_notification: true + ); + + $this->assertInstanceOf(Message::class, $result); + $this->assertEquals(TEST_CHAT_ID, $result->getChat()->getId()); + } + + + /** + * Tests sending a voice file using a URL. + * + * @return void + */ + public function testSendVoiceWithUrl(): void + { + $result = self::$bot->sendVoice( + chat_id: TEST_CHAT_ID, + voice: 'https://example.com/voice.ogg', + caption: 'Here is a voice message from a URL', + duration: 25 + ); + + $this->assertInstanceOf(Message::class, $result); + $this->assertEquals(TEST_CHAT_ID, $result->getChat()->getId()); + $this->assertEquals(25, $result->getVoice()->getDuration()); + } + + /** + * Tests sending a voice file with caption entities. + * + * @return void + */ + public function testSendVoiceWithCaptionEntities(): void + { + $captionEntities = [ + new MessageEntity(type: 'bold', offset: 0, length: 4), + new MessageEntity(type: 'italic', offset: 5, length: 5) + ]; + + $result = self::$bot->sendVoice( + chat_id: TEST_CHAT_ID, + voice: 'https://example.com/voice.ogg', + caption: 'This is a test', + caption_entities: $captionEntities + ); + + $this->assertInstanceOf(Message::class, $result); + $this->assertEquals(TEST_CHAT_ID, $result->getChat()->getId()); + $this->assertEquals('This is a test', $result->getCaption()); + } + + /** + * Tests sending a voice file with custom reply markup. + * + * @return void + */ + public function testSendVoiceWithReplyMarkup(): void + { + $replyMarkup = new InlineKeyboardMarkup(); + $replyMarkup->addRow( + InlineKeyboardButton::fromArray(['text' => 'Button 1', 'callback_data' => 'button1']), + InlineKeyboardButton::fromArray(['text' => 'Button 2', 'callback_data' => 'button2']) + ); + + try + { + $result = self::$bot->sendVoice( + chat_id: TEST_CHAT_ID, + voice: __DIR__ . DIRECTORY_SEPARATOR . 'sample' . DIRECTORY_SEPARATOR . 'ted.ogg', + reply_markup: $replyMarkup + ); + + $this->assertInstanceOf(Message::class, $result); + $this->assertEquals(TEST_CHAT_ID, $result->getChat()->getId()); + } + catch (TelegramException $e) + { + $this->fail('Failed to send voice message: ' . $e->getMessage()); + } + } + +} diff --git a/tests/TgBotLib/Methods/sample/ted.ogg b/tests/TgBotLib/Methods/sample/ted.ogg new file mode 100644 index 0000000..be6b812 Binary files /dev/null and b/tests/TgBotLib/Methods/sample/ted.ogg differ