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

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

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

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

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

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

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

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

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

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

bezumkin
Василий Наумкин
09.04.2024 01:45
Ошибка 500 Это не похоже на ошибку Nginx, это скорее всего ошибка PHP - надо смотреть его логи. Во...
futuris
Futuris
04.04.2024 05:56
Я просто немного запутался. Когда в абзаце &quot;Vesp/Core&quot; ты пишешь про &quot;новый trait Fil...
bezumkin
Василий Наумкин
20.03.2024 18:21
Volledig!
Андрей
14.03.2024 10:47
Василий! Как всегда очень круто! Моё почтение!
russelgal
russel gal
09.03.2024 17:17
А этот стоило написать хотя бы затем, чтобы получить комментарий от юзера, который ничего не писал ...
inetlover
Александр Наумов
27.01.2024 00:06
Василий, спасибо! Извини, тупанул.
bezumkin
Василий Наумкин
22.01.2024 04:43
Давай-давай!
bezumkin
Василий Наумкин
24.12.2023 11:26
Спасибо!
bezumkin
Василий Наумкин
27.11.2023 02:43
Ура!
bezumkin
Василий Наумкин
25.11.2023 08:30
Vesp тянет 2 зависимости: vesp-frontent для фронта и vesp-core для бэкенда. Их можно обновлять, но э...