keythkatz/telegram-bot-core

此包已被弃用且不再维护。未建议替代包。

Telegram Bot 框架

v1.1 2019-05-12 11:34 UTC

This package is auto-updated.

Last update: 2021-07-06 12:44:09 UTC


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());

键盘

InlineKeyboardMarkupReplyKeyboardMarkup 有辅助函数。

创建键盘有两种方式。第一种是直接创建

$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 处理,并且不会被跟踪。