Как сделать расширенное ветвление логики телеграм бота?
Делаю телеграм бота, не могу придумать лучшего варианта для отслеживания сообщений пользователя по условиям.
Допустим, есть схема, по которой нужно производить разные операции (условия кидаю по inline_keyboard для отслеживания callback_data):
[Найти по ФИО] или [Найти по email]
В первом случае выбрасывается сообщение "Введи ФИО", во втором, соответственно, "Введи email". Как отличить, что пользователь ввел email, а не ФИО и наоборот? Это лишь пример, костыли в виде поиска "@" в сообщении не сработают.
Сейчас работает очень тяжёлая конструкция с записью в отдельный на сервере файл массивов с айдишниками последних сообщений, увеличенными на 2, сравнение айдишника текущего сообщения с тем, что лежит в файле и, при совпадении, дергается его значение (которое привязывается к ниму по нажатию на конкретную кнопку). Выглядит как решение, но, на практике, довольно сложно поддерживать такую конструкцию, когда условие не одно.
А что вам мешает вести историю общения с конкретным пользователем? Записывать в нее что вы ему отправляли и что он отправлял вам в ответ, либо какие кнопки нажимал.
Stalker_RED, мне кажется, что в таком случае получаться громоздкие файлы истории... В таком случае, можете подсказать, пожалуйста, вариант ведения истории общения с пользователем, помимо массива в одном файле?
Кирилл Горелов, по поводу "Почему файлы, а не БД" - честно говоря, просто до чего получилось оперативно додуматься. По поводу регулярки - не получится, т.к. планируется большое количество таких разветвлений, так что email, введенный в разных ветвях может быть использован в разных функциях
shurshur, я и пытаюсь найти логику в этом плане и вижу только 2 варианта ведения истории переписки с пользователем в бд:
1. На каждого пользователя отдельная таблица;
2. В одной таблице, но переписка будет сериализованным массивом;
И оба нахожу странными
Саша, я опыт в таких ветвлениях не имел, но ввёл бы в вашем случае в таблицу чатов поле "state" для каждого "chat_id".
Соответственно в коде бота логика следующая:
Бот ищет соответствие чат_айди и его состояния при обращении юзера к боту.
Ну и дальше в коде можно сделать switch - case и действовать логике уже согласно состояния, в котором находится чат_айди. (Премеры состояний: ['work_with_email', 'work_with_name', 'anything_else', 'new']).
<?php
$state=getStateByChatID($chat_id);
switch($state){
case "work_with_email":
$bot->send($chat_id,"Введите мыло");
break;
case "work_with_name":
$bot->send($chat_id,"Введите ФИО");
break;
default:
\\видимо это новый чат
break;
}
Если юзер в чате жмёт кнопки по смыслу в сторону ввода e-mail и работы с ним - меняем state на work_with_email.
Внутри каждого Switch-case можете ветвить логику скольугодно глубже таким же методом добавив state такие как ["work_with_email-good_email",'work_with_email-bad_email'] (работаем уже с почтой но не правильно ввели мыло).
<?php
$state=getStateByChatID($chat_id);
switch($state){
case "work_with_email":
$bot->send($chat_id,"Введите мыло");
break;
case "work_with_email-good_email":
$bot->send($chat_id,"Введите правильное мыло");
break;
case "work_with_name":
$bot->send($chat_id,"Введите ФИО");
break;
default:
\\видимо это новый чат
break;
}
Подписался на вопрос, так как самому интересно как поступают другие.
Закинь еще кейсов, которые ты решаешь, сейчас придумаем. Потому что почта и фио слишком просто. И когда предлагаешь решение, говоришь, что не подходит.
Просто еще вариант для фио и почты кроме регулярки могу посоветовать использовать определение языка ввода текста рус/англ или вообще цифры, для номера телефона к примеру. Но уверен и это ты заброкуешь)
Всё это решается машиной состояний. Скорее всего он есть в вашем фреймворке по умолчанию. А если и нет - то написать его ничего не стоит - создавайте состояния и для каждого chat_id храните текущее состояние. В каждом состоянии есть функции-триггеры, которые приводят к переключению состояния на другое, попутно выполняя что-то полезное
Я о конечных автоматах узнал из этой статьи, в своё время
Получилось написать логику такого рода:
1. В таблице пользователей ботом (на строчку уникальный chat_id) появился новый столбец состояния;
2. В начале выполнения скрипта мы получаем state из таблицы для текущего пользователя;
3. Сравниваем его с нашими заготовками перед тем, как сравнивать текст сообщения;
4. При совпадении выполняется часть логики.
Так же стоит отметить момент, который мне помог (возможно это костыль, но до чего мозг додумал):
1. Записываем в переменную $strUserState полученное из БД состояние текущего пользователя для сравнения;
2. Объявляем пустую переменную $strState;
3. В случае, когда нам надо поменять состояние пользователя в БД, изменяем переменную $strState;
4. В конце скрипта - за пределами условий, то есть, в любом случае отправляем запрос в БД, где ставим у текущего пользователя state равный $strState.