Состояния (States)
Состояния позволяют управлять диалогами с пользователями. Пакет поддерживает два типа состояний: состояние чата и состояние пользователя.
Концепция состояний
Заголовок раздела «Концепция состояний»Состояние — это именованное состояние с опциональными данными, которое хранится в кеше. Оно позволяет:
- Создавать многошаговые диалоги
- Фильтровать роуты по текущему состоянию
- Сохранять контекст между сообщениями
Типы состояний
Заголовок раздела «Типы состояний»- Состояние чата — общее для всех пользователей в чате
- Состояние пользователя — индивидуальное для каждого пользователя
Работа с StateManager
Заголовок раздела «Работа с StateManager»Получение состояния
Заголовок раздела «Получение состояния»use HybridGram\Core\State\StateManagerInterface;
$stateManager = app(StateManagerInterface::class);$chat = $data->getChat();
// Получить состояние чата$chatState = $stateManager->getChatState($chat);if ($chatState) { $stateName = $chatState->getName(); $stateData = $chatState->getData();}
// Получить состояние пользователя$user = $data->getUser();if ($user) { $userState = $stateManager->getUserState($chat, $user);}Установка состояния
Заголовок раздела «Установка состояния»// Установить состояние чата$stateManager->setChatState( chat: $chat, state: 'awaiting_name', ttl: 3600, // Время жизни в секундах (опционально, по умолчанию 24 часа) data: ['step' => 1] // Дополнительные данные (опционально));
// Установить состояние пользователя$stateManager->setUserState( chat: $chat, user: $user, state: 'filling_profile', ttl: 7200, data: ['name' => 'John', 'age' => null]);Очистка состояния
Заголовок раздела «Очистка состояния»// Очистить состояние чата$stateManager->clearChatState($chat);
// Очистить состояние пользователя$stateManager->clearUserState($chat, $user);Проверка состояния
Заголовок раздела «Проверка состояния»// Проверить конкретное состояниеif ($stateManager->isChatInState($chat, 'awaiting_input')) { // ...}
if ($stateManager->isUserInState($chat, $user, 'filling_form')) { // ...}
// Проверить любое из состоянийif ($stateManager->isChatInAnyState($chat, ['awaiting_name', 'awaiting_email'])) { // ...}Использование в роутах
Заголовок раздела «Использование в роутах»Фильтрация роутов по состоянию
Заголовок раздела «Фильтрация роутов по состоянию»TelegramRouter::onTextMessage(function(TextMessageData $data) { // Этот роут сработает только если чат в состоянии 'awaiting_name'}, '*', function(TextMessageData $data) { $stateManager = app(\HybridGram\Core\State\StateManagerInterface::class); $chat = $data->getChat();
return $stateManager->isChatInState($chat, 'awaiting_name');});Или используя метод роута:
TelegramRouter::forBot('main') ->onMessage(function(TextMessageData $data) { // Обработка }) ->fromChatState('awaiting_name'); // Роут сработает только из этого состоянияУстановка состояния через роут
Заголовок раздела «Установка состояния через роут»TelegramRouter::onCommand('/start', function(CommandData $data) { $stateManager = app(\HybridGram\Core\State\StateManagerInterface::class); $stateManager->setChatState($data->getChat(), 'main_menu');
// Отправить ответ});Или через middleware:
use HybridGram\Http\Middlewares\SetStateTelegramRouteMiddleware;
TelegramRouter::onCommand('/start', function(CommandData $data) { // ...})->middleware(new SetStateTelegramRouteMiddleware('main_menu'));Примеры использования
Заголовок раздела «Примеры использования»Многошаговая форма
Заголовок раздела «Многошаговая форма»// Шаг 1: НачалоTelegramRouter::onCommand('/register', function(CommandData $data) { $stateManager = app(\HybridGram\Core\State\StateManagerInterface::class); $telegram = app(\HybridGram\Telegram\TelegramBotApi::class);
$stateManager->setChatState($data->getChat(), 'awaiting_name');
$telegram->sendMessage( $data->getChat()->id, 'Введите ваше имя:' );});
// Шаг 2: Получение имениTelegramRouter::forBot('main') ->onTextMessage(function(TextMessageData $data) { $stateManager = app(\HybridGram\Core\State\StateManagerInterface::class); $telegram = app(\HybridGram\Telegram\TelegramBotApi::class); $chat = $data->getChat();
$name = $data->message;
// Сохранить имя в данных состояния $stateManager->setChatState( chat: $chat, state: 'awaiting_email', data: ['name' => $name] );
$telegram->sendMessage($chat->id, 'Введите ваш email:'); }) ->fromChatState('awaiting_name');
// Шаг 3: Получение emailTelegramRouter::forBot('main') ->onTextMessage(function(TextMessageData $data) { $stateManager = app(\HybridGram\Core\State\StateManagerInterface::class); $telegram = app(\HybridGram\Telegram\TelegramBotApi::class); $chat = $data->getChat();
$currentState = $stateManager->getChatState($chat); $name = $currentState?->getData()['name'] ?? 'Unknown'; $email = $data->message;
// Сохранить пользователя // ... ваша логика сохранения
// Очистить состояние $stateManager->clearChatState($chat);
$telegram->sendMessage( $chat->id, "Спасибо, {$name}! Ваш email: {$email}" ); }) ->fromChatState('awaiting_email');Отмена процесса
Заголовок раздела «Отмена процесса»TelegramRouter::onCommand('/cancel', function(CommandData $data) { $stateManager = app(\HybridGram\Core\State\StateManagerInterface::class); $telegram = app(\HybridGram\Telegram\TelegramBotApi::class); $chat = $data->getChat();
// Очистить все состояния $stateManager->clearChatState($chat); if ($user = $data->getUser()) { $stateManager->clearUserState($chat, $user); }
$telegram->sendMessage($chat->id, 'Операция отменена');});Работа с данными состояния
Заголовок раздела «Работа с данными состояния»TelegramRouter::onTextMessage(function(TextMessageData $data) { $stateManager = app(\HybridGram\Core\State\StateManagerInterface::class); $chat = $data->getChat();
$currentState = $stateManager->getChatState($chat);
if ($currentState) { $stateData = $currentState->getData() ?? []; $step = ($stateData['step'] ?? 0) + 1;
// Обновить состояние с новыми данными $stateManager->setChatState( chat: $chat, state: $currentState->getName(), data: array_merge($stateData, ['step' => $step]) ); }})->fromChatState('filling_form');Исключение состояний
Заголовок раздела «Исключение состояний»Вы можете создать роут, который работает только если чат НЕ в определенном состоянии:
TelegramRouter::forBot('main') ->onCommand('/help', function(CommandData $data) { // Показывать справку }) ->exceptChatState('processing'); // Не показывать во время обработкиПользовательские состояния
Заголовок раздела «Пользовательские состояния»Для индивидуальной обработки каждого пользователя используйте состояния пользователя:
TelegramRouter::onCallbackQuery(function(CallbackQueryData $data) { $stateManager = app(\HybridGram\Core\State\StateManagerInterface::class); $chat = $data->getChat(); $user = $data->getUser();
// Установить состояние для конкретного пользователя $stateManager->setUserState( chat: $chat, user: $user, state: 'selecting_item', data: ['item_id' => $data->params[0]] );});Время жизни состояния
Заголовок раздела «Время жизни состояния»По умолчанию состояния хранятся 24 часа. Вы можете изменить это:
$stateManager->setChatState( chat: $chat, state: 'temporary_state', ttl: 300 // 5 минут);Что дальше?
Заголовок раздела «Что дальше?»- Middleware — использование middleware для управления состояниями
- Отправка сообщений — отправка ответов пользователям