Начало проекта

Это первая заметка из небольшого цикла по реальному применению 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

Открываем ваш локальный http://example-bot.test, и видим стандартную заглушку.

Фронтенд нам пока не нужен, но пусть будет. Интересует нас работа API, которую тоже легко проверить.

Открываем http://example-bot.test/api/user/profile, и в ответ мы должны получить "Authentication required" и код 401.

Если вы это видите, значит всё в порядке, API работает и можно продолжать работу.

Создаём бота

Телеграм управляет ботами через главного папу-бота, @BotFather. Вам нужно его добавить к себе, и создать нового бота, там всё очень просто.

Я сделал VespExampleBot, и получил токен для HTTP запросов к нему.

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, нам нужно:

  1. Создать контроллер в core/src/Controllers, который будет расширять Vesp\Controllers\Controller или его наследника.
  2. Прописать в нём нужные публичные методы.
  3. Указать этот контроллер для маршрута в core/routes.php
  4. Ну и присылать запросы на этот адрес.

Вот и всё!

Проверяем связь с ботом

Устанавливаем библиотеку для работы с 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.

Комментарии (3)
Сергей Лелеко
25.02.2022 06:06

О прикольно! я как раз начинал делать заготовку и очень интересно как должно быть реализовано правильно

gvozdbПавел Гвоздь
25.02.2022 06:56

Так как Vesp использует контейнер зависимостей, при обращении к такому контроллеру в него автоматически передаются требуемые классы

Wow! Это PHP-DI может такое вытворять? Просто круто!

P.S. Кажется цитаты у тебя никак не стилизуются в комментариях...

bezumkinВасилий Наумкин
25.02.2022 09:22

P.S. Кажется цитаты у тебя никак не стилизуются в комментариях...

Спасибо, поправил!

ЕвгенийК
09.04.2022 03:35
Это хорошо, что такая возможность есть и может быть использована. А то тенденция, мания, что-то в по...
begoodco1
07.04.2022 05:49
Зарегистрировался чтобы выразить благодарность за доступное и подробное описание процесса. Была возм...
bezumkin
Василий Наумкин
18.03.2022 12:35
Авторизация есть из коробки, для входа в базовую админку. Можно установить через composer и собрать ...
bezumkin
Василий Наумкин
10.03.2022 12:08
Ну, я имел в виду, что по закону можно =) А в реальности с валютой очевидные проблемы.
Сергей Лелеко
04.03.2022 06:12
О как! не знал! спасибо
bezumkin
Василий Наумкин
01.03.2022 15:32
Я делал одного бота на botman/botman, но из-за своей универсальности конкретно с Телеграм на нём раб...
bezumkin
Василий Наумкин
25.02.2022 09:22
P.S. Кажется цитаты у тебя никак не стилизуются в комментариях... Спасибо, поправил!
Electrica
Михаил
08.02.2022 11:19
Работает!
Алексей
09.01.2019 10:55
Насыщенный год ) От души поздравляю с ДР! Счастья, успехов и семейного благополучия! Жаль лимит заме...
septa rose
28.05.2018 22:16
hmmm, keren abis