From 00da3af39dae6e261aa6bcb6e2cc8736f97b3361 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 15 Aug 2025 20:15:33 +0300 Subject: [PATCH] Documentation and some fix --- README.md | 41 ++++++++--- docs/README.md | 102 ++++++++++++++++++++++++++ src/Api.php | 14 ++-- src/Laravel/MaxBotServiceProvider.php | 1 - tests/ApiFactoryMethodsTest.php | 4 - tests/ApiTest.php | 12 +++ 6 files changed, 154 insertions(+), 20 deletions(-) create mode 100644 docs/README.md diff --git a/README.md b/README.md index 15a662c..b80ff1b 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,11 @@ composer require bushlanov-dev/max-bot-api-client-php Отправка сообщения с клавиатурой ```php -$api = new \BushlanovDev\MaxMessengerBot\Api('YOUR_BOT_API_TOKEN'); +require __DIR__.'/vendor/autoload.php'; + +use BushlanovDev\MaxMessengerBot\Api; + +$api = new Api('YOUR_BOT_API_TOKEN'); $api->sendMessage( userId: 123, // ID пользователя получателя сообщения @@ -47,6 +51,26 @@ $api->sendMessage( ); ``` +Создание универсального обработчика обновлений + +```php +$dispatcher = $api->getUpdateDispatcher(); + +$dispatcher->onMessageCreated(function (MessageCreatedUpdate $update, Api $api) { + $api->sendMessage( + userId: $update->message->recipient->userId, + text: 'Привет!', + ); +}); +// или +$dispatcher->addHandler(UpdateType::BotStarted, function (BotStartedUpdate $update, Api $api) { + $api->sendMessage( + chatId: $update->chatId, + text: 'Я запущен!', + ); +}); +``` + Подписка на вэб хуки ```php @@ -61,19 +85,18 @@ $api->subscribe( ); ``` -Обработка хуков +Обработка обновлений ```php -$webhookHandler = $api->createWebhookHandler(); +$handler = $api->createWebhookHandler('super_secret'); // Обновления через вебхук +// ИЛИ +$handler = $api->createLongPollingHandler(); // Обновления через лонгполлинг -$webhookHandler->addHandler(UpdateType::BotStarted, function (BotStartedUpdate $update, Api $api) { - $api->sendMessage( - chatId: $update->chatId, - text: 'Я запущен!', - ); -}); +$handler->handle(); ``` +> ℹ️ С полной документацией [вы можете ознакомиться тут](./docs/README.md). + ## Реализованные методы #### Bots diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..7ea73d2 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,102 @@ +- [Быстрый старт](#Быстрый-старт) + - [Получение токена](#Получение-токена) + - [Установка библиотеки](#Установка-библиотеки) + - [Инициализация бота](#Инициализация-бота) +- [Информация о боте](#Информация-о-боте) + - `GET /me` (`getBotInfo`) - [*Получение информации о боте.*](#Получение-информации-о-боте) + - `PATCH /me` (`editBotInfo`) - [*Редактирование информации о боте.*](#Редактирование-информации-о-боте) +- Чаты + - `GET /chats` (`getChats`) - *Получение списка всех чатов бота.* + - `GET /chats/{chatLink}` (`getChatByLink`) - *Получение информации о чате по ссылке.* + - `GET /chats/{chatId}` (`getChat`) - *Получение информации о чате по ID.* + - `PATCH /chats/{chatId}` (`editChat`) - *Редактирование информации о чате.* + - `DELETE /chats/{chatId}` (`deleteChat`) - *Удаление чата.* + - `POST /chats/{chatId}/actions` (`sendAction`) - *Отправка действия в чат (например, "печатает...").* + - `GET /chats/{chatId}/pin` (`getPinnedMessage`) - *Получение закрепленного сообщения.* + - `PUT /chats/{chatId}/pin` (`pinMessage`) - *Закрепление сообщения.* + - `DELETE /chats/{chatId}/pin` (`unpinMessage`) - *Открепление сообщения.* + - `GET /chats/{chatId}/members/me` (`getMembership`) - *Получение информации о членстве бота в чате.* + - `DELETE /chats/{chatId}/members/me` (`leaveChat`) - *Выход бота из чата.* + - `GET /chats/{chatId}/members/admins` (`getAdmins`) - *Получение администраторов чата.* + - `POST /chats/{chatId}/members/admins` (`addAdmins`) - *Назначение администраторов чата.* + - `DELETE /chats/{chatId}/members/admins/{userId}` (`deleteAdmins`) - *Снятие прав администратора.* + - `GET /chats/{chatId}/members` (`getMembers`) - *Получение участников чата.* + - `POST /chats/{chatId}/members` (`addMembers`) - *Добавление участников в чат.* + - `DELETE /chats/{chatId}/members` (`deleteMember`) - *Удаление участника из чата.* +- Получение обновлений + - `GET /subscriptions` (`getSubscriptions`) - *Получение списка Webhook-подписок.* + - `POST /subscriptions` (`subscribe`) - *Создание Webhook-подписки.* + - `DELETE /subscriptions` (`unsubscribe`) - *Удаление Webhook-подписки.* + - `GET /updates` (`getUpdates`) - *Получение обновлений через Long-Polling.* +- Загрузка файлов + - `POST /uploads` (`getUploadUrl`) - *Получение URL для загрузки файла.* +- Сообщения + - `GET /messages` (`getMessages`) - *Получение списка сообщений из чата.* + - `POST /messages` (`sendMessage`) - *Отправка сообщения.* + - `PUT /messages` (`editMessage`) - *Редактирование сообщения.* + - `DELETE /messages` (`deleteMessage`) - *Удаление сообщения.* + - `GET /messages/{messageId}` (`getMessageById`) - *Получение сообщения по ID.* + - `GET /videos/{videoToken}` (`getVideoAttachmentDetails`) - *Получение детальной информации о видео.* + - `POST /answers` (`answerOnCallback`) - *Ответ на нажатие callback-кнопки.* + +## Быстрый старт + +> Если вы новичок, то можете прочитать [официальную документацию](https://dev.max.ru/), написанную разработчиками Max. + +### Получение токена + +Откройте диалог с [MasterBot](https://max.ru/MasterBot), следуйте инструкциям и создайте нового бота. После создания +бота MasterBot отправит вам токен. + +### Установка библиотеки + +```bash +composer require bushlanov-dev/max-bot-api-client-php +``` + +### Инициализация бота + +Единственной обязательной настройкой является токен вашего бота. +⚠️ Никогда, и ни при каких обстоятельствах не храните токен в коде. ⚠️ +Используйте переменные окружения! + +```php +require __DIR__.'/vendor/autoload.php'; + +use BushlanovDev\MaxMessengerBot\Api; + +$api = new Api('YOUR_BOT_API_TOKEN'); +``` + +Так же вы можете создать экземпляр бота гибко настроив все зависимости под свои нужды. + +```php +$api = new Api( + client: new Client(...), + modelFactory: new ModelFactory(), + logger: new YourPsrLogger(), +); +``` + +## Информация о боте + +### Получение информации о боте + +```php +$botInfo = $api->getBotInfo(); +``` + +### Редактирование информации о боте + +Обратите внимание что данный метод отправляется PATCH запросом. Это значит, что будут обновлены только переданные +поля. +В следующем примере мы изменяем только название бота и отчистим его описание. Остальные поля останутся неизменными. + +```php +$botInfo = $api->editBotInfo( + new BotPatch( + name: 'Супер бот', + description: null, + ) +); +``` diff --git a/src/Api.php b/src/Api.php index 487fb2a..6b335ad 100644 --- a/src/Api.php +++ b/src/Api.php @@ -47,7 +47,7 @@ use RuntimeException; */ class Api { - public const string LIBRARY_VERSION = '1.0.0'; + public const string LIBRARY_VERSION = '1.0.1'; public const string API_VERSION = '0.0.6'; @@ -85,21 +85,23 @@ class Api /** * Api constructor. * - * @param string $accessToken Your bot's access token from @MasterBot. + * @param string|null $accessToken Your bot's access token from @MasterBot. * @param ClientApiInterface|null $client Http api client. * @param ModelFactory|null $modelFactory The model factory. * @param LoggerInterface|null $logger PSR LoggerInterface. - * @param UpdateDispatcher|null $updateDispatcher The update dispatcher. * * @throws InvalidArgumentException */ public function __construct( - string $accessToken, + ?string $accessToken = null, ?ClientApiInterface $client = null, ?ModelFactory $modelFactory = null, ?LoggerInterface $logger = null, - ?UpdateDispatcher $updateDispatcher = null, ) { + if (empty($accessToken) && $client === null) { + throw new InvalidArgumentException('You must provide either an access token or a client.'); + } + $this->logger = $logger ?? new NullLogger(); if ($client === null) { @@ -130,7 +132,7 @@ class Api $this->client = $client; $this->modelFactory = $modelFactory ?? new ModelFactory(); - $this->updateDispatcher = $updateDispatcher ?? new UpdateDispatcher($this); + $this->updateDispatcher = new UpdateDispatcher($this); } /** diff --git a/src/Laravel/MaxBotServiceProvider.php b/src/Laravel/MaxBotServiceProvider.php index dc362de..a089ef9 100644 --- a/src/Laravel/MaxBotServiceProvider.php +++ b/src/Laravel/MaxBotServiceProvider.php @@ -102,7 +102,6 @@ class MaxBotServiceProvider extends ServiceProvider $app->make(ClientApiInterface::class), $app->make(ModelFactory::class), $app->make(LoggerInterface::class), - null, ); }); diff --git a/tests/ApiFactoryMethodsTest.php b/tests/ApiFactoryMethodsTest.php index 2fef8c0..b734687 100644 --- a/tests/ApiFactoryMethodsTest.php +++ b/tests/ApiFactoryMethodsTest.php @@ -35,15 +35,11 @@ final class ApiFactoryMethodsTest extends TestCase $this->modelFactoryMock = $this->createMock(ModelFactory::class); $this->loggerMock = $this->createMock(LoggerInterface::class); - $apiForDispatcher = $this->createMock(Api::class); - $dispatcher = new UpdateDispatcher($apiForDispatcher); - $this->api = new Api( 'fake-token', $this->clientMock, $this->modelFactoryMock, $this->loggerMock, - $dispatcher, ); } diff --git a/tests/ApiTest.php b/tests/ApiTest.php index 0f4b051..af3893f 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -1980,4 +1980,16 @@ final class ApiTest extends TestCase $this->assertSame($expectedDetails, $result); } + + #[Test] + public function constructorThrowsExceptionWhenNoTokenAndNoClientProvided(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('You must provide either an access token or a client.'); + + new Api( + accessToken: null, + client: null + ); + } }