keythkatz / telegram-bot-core
Telegram Bot 框架
Requires
- php: ^7.2
- ext-json: *
- guzzlehttp/guzzle: ^6
- monolog/monolog: ^1
- telegram-bot/api: ^2.3
Requires (Dev)
- phpunit/phpunit: ^8
README
遵守 Telegram Bot API 的面向对象的 Telegram Bot 框架。示例机器人可在 KeythKatz/Stanley 找到。
要求
- PHP 7.2 及以上
安装
使用 Composer
composer require keythkatz/telegram-bot-core
快速入门
创建一个机器人类
class ExampleBot extends \KeythKatz\TelegramBotCore\TelegramBotCore { protected function registerHandlers() { // We will fill in this part later } }
命令
每个命令都是其自己的类。这里我们创建一个简单的回声命令。
class EchoCommand extends \KeythKatz\TelegramBotCore\Command { // Name of the command, /echo protected $name = "echo"; // What text to show for the command when doing /help. // Set to null to hide the command. protected $helpText = "Repeat after me"; /** * What to do when the command is called. * @param string $arguments The arguments following the command as a string. * @param Message $message Raw Message object that triggered this command. */ public function process($arguments, $message) { $reply = $this->sendMessageReply(); $reply->setText($arguments); $response = $reply->send(); // Get Telegram's response } }
接下来,将命令添加到您的机器人的 registerHandlers()
protected function registerHandlers() { $this->addCommand(new EchoCommand()); }
设置 Webhook
从您告诉 Telegram 发送更新的地方调用您的机器人
$bot = new ExampleBot( "@BotUsername", "BotToken", [StorageDirectory], // Storage Directory if you are using Conversations [Loggging = false], // Set to true if enabling logging [LogDirectory], [Testing = false] // Set to true to not send data to Telegram servers, instead storing requests inside the $testOutput and $testAttachment variables ); $bot->webhook();
就是这样!现在 /echo
和 /help
应该可以工作了。
文档
方法和类型,Telegram API
此库遵循官方 Telegram API 文档。位于 Method
命名空间下的类遵循官方 API 的 可用方法 部分。位于 Type
命名空间下的类遵循 可用类型。
Telegram 中的参数使用 snake_case。然而,此库使用 camelCase,但所有名称都是相同的。要设置参数,请使用设置器。
此库使用 telegram-bot/api 库来解析接收到的更新。两个库中的类型以相同的方式工作,具有获取器和设置器。
示例:从命令发送内联键盘
$message = $this->sendMessageReply(); $message->setText("Hello World"); // Traditional way of setting up a keyboard. Helper functions are available. // (See Keyboard section in the docs) $keyboard = new InlineKeyboardMarkup([[["Click Me" => "https://google.com"]]]); $message->setReplyMarkup($keyboard); $message->send();
TelegramBotCore
abstract class TelegramBotCore { /** * Token given by telegram for the bot. * @var string */ protected static $token = null; // Override this /** * Username of the bot, e.g. @exampleBot * @var string */ protected static $username = null; // Override this /** * Directory to store conversation files * @var string */ protected static $storageLocation = __DIR__; // Optionally override this, but override if you are using Conversations /** * Add all your commands and handlers within this function. */ abstract protected function registerHandlers(); /** * Call this function to turn on the bot when processing via webhooks. */ public static function webhook(): void }
处理程序 - 命令
abstract class Command extends ForwardableHandler { protected $name = null; // Override this protected $helpText = ""; // Optionally override this /** * What to do when the command is called. * @param string $arguments Arguments entered by the user. * @param \TelegramBot\Api\Types\Message $message Message object that triggered this command. */ abstract public function process($arguments, $message); }
要创建一个新的命令,扩展 \KeythKatz\TelegramBotCore\Command
,并用命令的名称覆盖 $name
,该名称将被 /name
触发。可选地覆盖 $helpText
以提供帮助文本,该文本将通过自动生成的 /help
显示。如果将其保留为 null 或空字符串,则命令将不会显示在 /help
中。
Command
类有辅助函数,也与 Telegram API 方法相关联
// Create a new SendMessage linked to the bot. $message = $this->sendMessage(); // Add Reply to any method name to create it with the chatId prefilled. // Set $quoteOriginal to true to reply directly to the triggering message. $message = $this->sendMessageReply($quoteOriginal = false); // Forward the triggering message to another chat immediately. // Set $disableNofication to true to send the message silently. $this->forwardMessage($toChatId, $disableNotification = false); // And other API methods...
在任何类中,您也可以使用以下方式直接与机器人或触发消息交互
$this->bot; $this->message;
将其添加到机器人的 registerHandlers
函数中,如下所示
$this->addCommand(new EchoCommand());
要从用户输入中调用命令,请从任何处理程序中调用 $this->runCommand(new EchoCommand(), $arguments)
。默认情况下,$arguments
是空字符串,是可选的。
处理器 - 回调查询处理器
abstract class CallbackQueryHandler extends BaseHandler { /** * What to do when the bot receives a CallbackQuery. * @param CallbackQuery $query received CallbackQuery. * @param \TelegramBot\Api\Types\Message $message Message that the callback button originated from. * May be null if the message is too old. */ abstract public function process(CallbackQuery $query, \TelegramBot\Api\Types\Message $message); }
CallbackQueryHandler
与命令类似。在你的自定义类中覆盖 process()
函数。
在类的任何地方,您也可以使用以下方式直接与机器人或触发查询交互:
$this->bot; $this->query;
将其添加到机器人的 registerHandlers
函数中,如下所示
$this->setCallbackQueryHandler(new CqHandler());
处理器 - 通用消息处理器
abstract class GenericMessageHandler extends ForwardableHandler { /** * What to do when the command is called. * @param string $arguments Arguments entered by the user. * @param \TelegramBot\Api\Types\Message $message Message object that triggered this command. */ abstract public function process(\TelegramBot\Api\Types\Message $message); }
GenericMessageHandler
与命令类似。在你的自定义类中覆盖 process()
函数。
在任何类中,您也可以使用以下方式直接与机器人或触发消息交互
$this->bot; $this->message;
将其添加到机器人的 registerHandlers
函数中,如下所示
$this->setGenericMessageHandler(new DefaultMessageHandler());
键盘
InlineKeyboardMarkup
和 ReplyKeyboardMarkup
有辅助函数。
创建键盘有两种方式。第一种是直接创建
$keyboard = new InlineKeyboardMarkup([[["Click Me" => "https://google.com"]]]); // or $keyboard = new InlineKeyboardMarkup(); $keyboard->setInlineKeyboard([[["Click Me" => "https://google.com"]]]);
第二种方式是使用辅助函数
$keyboard = new InlineKeyboardMarkup(); // or ReplyKeyboardMarkup // Create a new button $button = new InlineKeyboardButton($text); // or KeyboardButton $button->setCallbackData("12345"); // or any other field in the telegram docs // Add to the keyboard $keyboard->addButton($button); // Add a new row. Added buttons after this will be on the new row. $keyboard->addRow(); // Add a button to any row, 0-indexed $keyboard->addButton($button, 0);
对话
abstract class Conversation extends ForwardableHandler { /** * Chat ID that the conversation belongs to. * @var int */ protected $chatId; /** * ID of the user that initiated the conversation. * @var int */ protected $userId; /** * Initialise stages here by calling $this->addStage() for each stage. */ abstract public function initialize(); /** * Add a stage. * @param string $name Name of the stage. * @param string $message Message to send and ask a reply to. * @param callable $callback Callback that is called with the replying message as a parameter. */ protected function addStage(string $name, string $message, callable $callback): void /** * Save data that will be persistant across conversations. * @param string $name Name of the data. * @param anything $data Data to be stored. */ protected function saveData(string $name, $data): void /** * Load saved data. * @param string $name Name of the data. * @return anything Saved data. */ protected function loadData(string $name) /** * Repeat the current stage, for example on invalid input. */ protected function repeatStage(): void /** * Set the current stage, i.e. move on in the conversation. * @param string $name Name of the stage to move to. */ protected function setStage(string $name): void }
对话允许用户通过多条消息进行输入。它们通过“阶段”来处理。对于每个阶段,提供一个名称、要发送并由用户回复的消息,以及回复的回调,它接受一个 \TelegramBot\Api\Types\Message
对象。添加的第一个阶段将是对话的起点。
可以在对话中保存和加载数据,并且数据存储在指定目录的文件中。
示例
class ExampleConversation extends \KeythKatz\TelegramBotCore\Conversation { public function initialize() { $this->addStage("start", "Enter a message.", function($message) { if ($message->getText() === null) { // No text found, show an error and repeat the question. $reply = $this->sendMessageReply(); $reply->setText("You did not enter anything."); $reply->send(); $this->repeatStage(); } else { $this->saveData("message 1", $message->getText()); $this->setStage("next message"); } } ); $this->addStage("next message", "Enter another message.", function($message) { if ($message->getText() === null) { // No text found, show an error and repeat the question. $reply = $this->sendMessageReply(); $reply->setText("You did not enter anything."); $reply->send(); $this->repeatStage(); } else { $text1 = $this->loadData("message 1"); $text2 = $message->getText(); $reply = $this->sendMessageReply(); $reply->setText("You entered $text1 and $text2"); $reply->send(); } } ); } }
从任何处理器(包括其他对话)调用 $this->startConversation(new ExampleConversation())
来启动它。
Bot: Enter a message.
User: 123
Bot: Enter another message.
User: abc
Bot: You entered 123 and abc
交互式消息
abstract class InteractiveMessage extends BaseHandler { /** * The callback query that triggered this handler. * @var \TelegramBot\Api\Types\CallbackQuery */ protected $callbackQuery; /** * ID of the chat that the message was sent in. * @var int */ protected $chatId; /** * ID of the message that this object is handling. * @var int */ protected $messageId; /** * @param \KeythKatz\TelegramBotCore\Method\Method $baseMethod Method that will be sent. Must be able to setReplyMarkup on it. */ public function __construct(\KeythKatz\TelegramBotCore\Method\Method $baseMethod = null) /** * What to do when a CallbackQuery belonging to this message is received. * @param \TelegramBot\Api\Types\CallbackQuery $callbackQuery CallbackQuery received. * @param \TelegramBot\Api\Types\Message $message Message attached to the CallbackQuery */ abstract public function process(\TelegramBot\Api\Types\CallbackQuery $callbackQuery, \TelegramBot\Api\Types\Message $message); /** * Set the inline keyboard for the message. * @param \KeythKatz\TelegramBotCore\Type\InlineKeyboardMarkup $keyboard InlineKeyboardMarkup to send with the message. */ public function setReplyMarkup(\KeythKatz\TelegramBotCore\Type\InlineKeyboardMarkup $keyboard): void /** * Send the message. The InteractiveMessage and its data will then be saved locally. */ public function send(): void /** * Save data that will be persistent. * @param string $name Name of the data. * @param anything $data Data to be stored. */ public function saveData(string $name, $data): void /** * Load saved data. * @param string $name Name of the data. * @return anything Saved data. */ public function loadData(string $name) /** * Create a new EditMessageText object. The chatId and messageId are automatically filled. * @return [type] [description] */ public function editMessageText(): \KeythKatz\TelegramBotCore\Method\EditMessageText }
交互式消息允许您轻松处理消息的回调查询。它们与对话类似,并允许您存储在整个消息生命周期中可用的数据。
输入文件
在 Telegram API 中指定 InputFile
的任何地方,您可以直接发送资源,例如 fopen($file, 'r')
。或者,您可以将它封装在 InputFile
类中,例如 new InputFile(fopen($file, 'r'))
。
异步
此库支持通过 Guzzle/Promises
同步发送消息。要异步发送消息,只需将 send()
更改为 sendAsync()
。两种方法都返回 Telegram 的响应,无论它是根据 Telegram API 的什么。
清单
机器人功能
- 处理命令
- 处理回调查询
- 处理不带命令的通用消息
- 阻止用户
方法
- sendMessage
- forwardMessage
- sendPhoto
- sendAudio
- sendDocument
- sendVideo
- sendAnimation
- sendVoice
- sendVideoNote
- sendMediaGroup
- sendLocation
- editMessageLiveLocation
- stopMessageLiveLocation
- sendVenue
- sendContact
- sendPoll
- sendChatAction
- getFile
- ... 目前不处理聊天和贴纸功能
- answerCallbackQuery
- editMessageText
- editMessageCaption
- editMessageMedia
- editMessageReplyMarkup
- stopPoll
- deleteMessage
类型
- ReplyKeyboardMarkup
- KeyboardButton
- ReplyKeyboardRemove
- InlineKeyboardMarkup
- InlineKeyboardButton
- 强制回复
- 输入媒体
- 输入媒体图片
- 输入媒体视频
- 输入文件
只接收类型(来自 Update 对象)由 telegram-bot/api
处理,并且不会被跟踪。