Сессии в Telegram-боте на Laravel

День добрый, уважаемые читатели!

В процессе написания бота для Telegram у меня возникла необходимость сохранять сессионные данные, привязанные к пользователю, который общается с ботом. Это может потребоваться для запоминания «стадии» диалога, если процедура, которую инициировал пользователь, является многоступенчатой, и нужно помнить состояние этого диалога. С одной стороны, есть возможность решить данную проблему «сложно», в каждом подобном диалоге имея свой механизм запоминания. Но это «хардкорный» путь, имеющий множество недостатков. Гораздо более элегантным способом была бы возможность использовать встроенный в Laravel механизм сессий, который используется в обычных HTTP-запросах. Как это сделать, я и попытаюсь объяснить в данной статье.

Начнем с того, что запросы из Telegram API являются stateless, то есть не поддерживают состояние. И в отличие от запросов из браузера здесь нет никаких cookies, в которых можно было бы хранить ID сессии. Но зато с каждым запросом мы так или иначе можем получить ID пользователя, присылающего сообщение — его то и можно использовать в качестве ID сессии.

Далее встает вопрос: как указать Laravel, чтобы сессия инициировалась по нужному нам механизму, вернее, чтобы инициировалась сессия с нужным нам ID? Это, по сути, и есть основная проблема.

Сначала напомню, как инициализируется «обычная» сессия в Laravel. Каждый «web» машрут, который вы прописываете, относится к группе «web» (простите за тавтологию), и один из посредников («middleware»), отрабатывающих для всех маршрутов этой группы — это StartSession. Именно этот middleware отвечает за инициализацию сессии. Как вы уже, наверное, догадались, нам необходимо для нашего WebHook’а, который «дергается» Telgram API, прописать «свой» middleware, который проинициализирует сессию нужным нам образом. «Свой» я взял в кавычки, потому как это будет не полностью свой middleware (было бы неразумно писать «с нуля» собственного посредника), а лишь слегка переопределенный стандартный StartSession. Иными словами, наш midlleware, который назовем StartTelegramSession, будет наследоваться от StartSession и переопределять лишь ту логику, которая отвечает за инициализацию сессии, в нужном месте подставив вместо ID из кукисов ID пользователя из Telegram.

Изучив исходный StartSession, видим, что таким местом является метод getSession(Request $request) :

Поэтому в первую очередь, в нашем StartTelegramSession переопределяем этот метод:

Теперь в любом месте обработки сообщения от Telegram у нас есть стандартный механизм сессий Laravel. Осталось одна мелочь: не забыть сохранить сессию по завершении запроса. Для этого немного переопределим «основной» метод middleware, а именно — handle() :

Итого, полный исходный код нашего класса выглядит так:

Ну и напоследок, осталось прикрепить этот Middleware вместо стандартного StartSession к WebHook’у. Сделать это можно, создав отдельную группу маршрутов, в которой прописать этот посредник. Соотв-но, в app/Http/Kernel.php  добавляем новую группу:

Далее в app/Providers/RouteServiceProvider.php :

А сам WebHook-маршрут прописываем в routes/telegram.php .

На этом все. Спасибо за внимание и приятного кодинга вам 🙂

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.