Начало проекта
Это первая заметка из небольшого цикла по реальному применению Vesp. В качестве примера мы напишем и запустим Telegram бота, который будет делать что-то несложное.
Понятное дело, что за работу с Телеграм будет отвечать готовая библиотека, но в остальном мы всё напишем сами.
Я буду предполагать, что у вас уже есть своё рабочее окружение, и вы можете запускать на своей машине PHP с NodeJS.
Лично я использую последнюю MacOS с Homebrew, Laravel Valet, MySQL 8, PHP 7.4 и Node 17.5. Если нужна отдельная заметка по их установке и настройке - напишите в комментариях.
Подготовка
Если вы тоже используете Valet, то установите мой драйвер для работы с Vesp.
Итак, создаём новый проект в директории ExampleBot:
composer create-project vesp/vesp ExampleBot
Эта команда скачает и установит все нужные зависимости для PHP и Node.
Создаём локальный домен example-bot.test для работы:
cd ExampleBot
valet link example-bot
Переименовываем .env в .env.local, чтобы избежать возможных конфликтов при будущем деплое на рабочий сервер
mv .env .env.local
И редактируем файл, примерно так:
APP_NAME="Example Bot"
SITE_URL=http://example-bot.test/
API_URL=http://example-bot.test/api/
CORS=1 # Разрешаем кросс-доменные запросы к API
DB_DRIVER=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_PREFIX=app_
DB_DATABASE=ExampleBot
DB_USERNAME=root
DB_PASSWORD=root
DB_CHARSET=utf8mb4
DB_COLLATION=utf8mb4_general_ci
DB_FOREIGN_KEYS=1
JWT_SECRET=secret
JWT_EXPIRE=2592000
JWT_MAX=3
UPLOAD_DIR=/Users/developer/Projects/ExampleBot/upload/
CACHE_DIR=/Users/developer/Projects/ExampleBot/tmp/
Теперь можно собрать фронтенд и проверить работу проекта:
composer node:generate
Фронтенд нам пока не нужен, но пусть будет. Интересует нас работа API, которую тоже легко проверить.
Открываем http://example-bot.test/api/user/profile, и в ответ мы должны получить "Authentication required" и код 401.
Если вы это видите, значит всё в порядке, API работает и можно продолжать работу.
Создаём бота
Телеграм управляет ботами через главного папу-бота, @BotFather. Вам нужно его добавить к себе, и создать нового бота, там всё очень просто.
Cоздаём новые переменные в .env.local, чтобы затем использовать их в своём коде
BOT_USERNAME=ВашеИмяБота
BOT_API_KEY=ВашСекретныйТокен
Если в будущем нужно будет заменить токен, то поменять его придётся только в файле настроек.
Всё, телеграм-бот уже работает, только ничего не делает, потому что мы не написали программу, которая будет с ним дружить.
Логика работы API Vesp
Для получения и обработки запросов Vesp использует Slim 4.
- Все запросы прилетают в www/api.php
- Там Slim инициализируется через PHP-DI, что сразу даёт нам поддержку контейнера зависимостей в контроллерах
- Затем добавлятся маршруты с контроллерами из core/routes.php
- Slim сверяет запрос с указанными маршрутами и передаёт его подходящему контроллеру
- Контроллер обрабатывает запрос и возвращает ответ через $this->success() или $this->failure() в формате JSON.
Согласно спецификации HTTP, запросы могут быть отправлены разными методами: GET, POST, PUT, PATCH, DELETE и OPTIONS.
Ответы должны соответствовать PSR-7, за что также отвечает Slim 4.
Нам остаётся только добавить в котроллер публичную функцию для нужного запроса с его именем, например для GET:
public function get(): Psr\Http\Message\ResponseInterface
{
return $this->success('Hello World!');
}
Как следуюет из сигнатуры функции, ответ обязательно должен быть экземпляром Psr\Http\Message\ResponseInterface.
Для POST и PATCH это будут соответственно:
public function post(): Psr\Http\Message\ResponseInterface
{
// ...
}
public function patch(): Psr\Http\Message\ResponseInterface
{
// ...
}
Если кто-то запросит метод, которого в котроллере нет, то получит ошибку 405 Method Not Allowed.
Итого, для поддержки любых запросов в API, нам нужно:
- Создать контроллер в core/src/Controllers, который будет расширять Vesp\Controllers\Controller или его наследника.
- Прописать в нём нужные публичные методы.
- Указать этот контроллер для маршрута в core/routes.php
- Ну и присылать запросы на этот адрес.
Вот и всё!
Проверяем связь с ботом
Устанавливаем библиотеку для работы с API Телеграм:
composer require longman/telegram-bot
Создаём сервис для работы с API, чтобы его можно было легко использовать в контроллерах Vesp.
Создаём файл core/src/Services/Telegram.php:
<?php
namespace App\Services;
class Telegram extends \Longman\TelegramBot\Telegram
{
public function __construct()
{
parent::__construct(getenv('BOT_API_KEY'), getenv('BOT_USERNAME'));
}
}
Как видно, наш класс расширяет основной класс библиотеки, всего с одним изменением - он сразу указывает наши переменные для бота. То есть, когда мы будем вызывать наш сервис, он всегда будет инициализировать именно нашего бота, без лишних вопросов.
Теперь пишем простенький контроллер для теста core/src/Controllers/Web/Test.php. Он не будет требовать никакой авторизации, поэтому кладём его в раздел Web:
<?php
namespace App\Controllers\Web;
use App\Services\Telegram;
use Longman\TelegramBot\Request;
use Psr\Http\Message\ResponseInterface;
use Vesp\Controllers\Controller;
use Vesp\Services\Eloquent;
class Test extends Controller
{
protected Telegram $telegram;
public function __construct(Eloquent $eloquent, Telegram $telegram)
{
parent::__construct($eloquent);
$this->telegram = $telegram;
}
public function get(): ResponseInterface
{
$response = Request::getMe();
if ($response->isOk()) {
return $this->success($response->getResult());
}
return $this->failure($response->getDescription(), $response->getErrorCode());
}
}
Тут нужно обратить внимание, что мы расширили конструктор контроллера и помимо стандартной загрузки Eloquent для работы с базой данных, добавили еще и наш новый сервис Telegram.
Так как Vesp использует контейнер зависимостей, при обращении к такому контроллеру в него автоматически передаются требуемые классы.
Таким образом можно загружать любые свои сервисы в контроллеры и там их использовать.
Осталось только указать новый маршрут с нашим контроллером в core/routes.php внутри группы api, сразу после подгруппы admin:
$group->group(
'/web',
static function (RouteCollectorProxy $group) {
$group->get('/test', App\Controllers\Web\Test::class);
}
);
Теперь можно делать запрос по адресу http://example-bot.test/api/web/test и, если вы всё сделали верно, то получите ответ с данными бота.
У меня он вот такой:
Это значит, что наша система не только работает, но и связана с ботом, и может им управлять.
Продолжение следует!
Полный код проекта в текущем виде находится на GitHub.
0
👍
👎
❤️
🔥
😮
😢
😀
😡
667
25.02.2022, 11:57:34
3 комментария
Сергей Лелеко
25.02.2022, 12:06:04
О прикольно! я как раз начинал делать заготовку и очень интересно как должно быть реализовано правильно
Павел Гвоздь
25.02.2022, 12:56:07
Wow! Это PHP-DI может такое вытворять? Просто круто!
P.S. Кажется цитаты у тебя никак не стилизуются в комментариях...
Василий Наумкин
25.02.2022, 15:22:38
Спасибо, поправил!
bezumkin.ru
Личный сайт Василия Наумкина
Прямой эфир
Василий Наумкин
01.07.2024, 11:56:41
Да, верно, именно так.
А в контроллере, скорее всего, ловить данные методом post.
Василий Наумкин
26.06.2024, 09:38:15
О, точно, вылезает если не залогинен.
Спасибо, исправил!
Василий Наумкин
09.04.2024, 04:45:01
> Ошибка 500
Это не похоже на ошибку Nginx, это скорее всего ошибка PHP - надо смотреть его логи.
...
russel gal
09.03.2024, 20:17:18
> А этот стоило написать хотя бы затем, чтобы получить комментарий от юзера, который ничего не писал...
Александр Наумов
27.01.2024, 03:06:18
Василий, спасибо!
Извини, тупанул.