Compare commits

..

16 Commits

Author SHA1 Message Date
Alex e5a6ec40fc Update composer 2026-06-27 16:40:46 +03:00
Alex 9eb8783f40 Merge pull request #36 from tofers/patch-1
Change url address
2026-06-27 09:38:23 +03:00
Konstantin 40de64593b Change url address
Для корректной работы ваших чат-ботов и мини-приложений до 19 июля 2026 необходимо перенаправить HTTP-запросы с домена platform-api.max.ru на platform-api2.max.ru, а также добавить сертификат Минцифры в список доверенных
2026-06-25 12:53:49 +03:00
Alex dfe2147cd1 tag 1.6.3 2026-04-26 20:36:38 +03:00
Alex 3d958f3f92 Update tests 2026-04-26 20:28:07 +03:00
Alex f40dc12d0c Merge pull request #32 from imperiumbee/master
New button type clipboard
2026-04-26 19:04:43 +03:00
imperiumbee b726c96366 Merge branch 'BushlanovDev:master' into master 2026-04-25 18:41:05 +03:00
imperiumbee c41221cec7 New button type clipboard 2026-04-25 18:38:55 +03:00
Alex 4fdfca53ee tag 1.6.2 2026-04-17 20:21:29 +03:00
Alex 9df8ed8817 Merge pull request #31 from spyke113/master
add `psr/log` versions
2026-04-16 14:46:34 +03:00
szuev 455b36ba2a add psr/log versions 2026-04-16 13:05:58 +03:00
Alex efd6261490 Added chat admin permissions 2026-04-15 22:10:15 +03:00
Alex dd295efc3d tag 1.6.0 2026-03-22 09:23:35 +03:00
Alex 85231b0962 Removed deprecated DataAttachment 2026-03-21 09:44:40 +03:00
Alex 40742ddc60 Removed deprecated ReplyKeyboardAttachment #27 2026-03-20 22:55:36 +03:00
Alex 1e48123ee3 Updated webhook documentation #26 2026-03-13 20:54:49 +03:00
31 changed files with 141 additions and 405 deletions
+3 -1
View File
@@ -16,6 +16,8 @@
> Если вы новичок, то можете прочитать [официальную документацию](https://dev.max.ru/), написанную разработчиками Max.
> ℹ️ С полной документацией [вы можете ознакомиться тут](./docs/README.md).
### Получение токена
Откройте диалог с [MasterBot](https://max.ru/MasterBot), следуйте инструкциям и создайте нового бота. После создания
@@ -103,7 +105,7 @@ $dispatcher->addHandler(UpdateType::BotStarted, function (BotStartedUpdate $upda
```php
$api->subscribe(
url: 'https://example.com/webhook', // URL на который будут приходить хуки
url: 'https://example.com/webhook', // HTTPS URL на который будут приходить хуки
secret: 'super_secret', // Секретная фраза для проверки хуков
updateTypes: [
// Типы хуков которые вы хотите получать (либо ничего не указывать, чтобы получать все)
+3 -3
View File
@@ -28,15 +28,15 @@
"psr/http-client": "^1.0",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.0||^2.0",
"psr/log": "^3.0"
"psr/log": "^1.1||^2.0||^3.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.77",
"bushlanov-dev/php-coverage-badger": "^2.1",
"laravel/framework": "^11.0",
"laravel/framework": "^12.0",
"mikey179/vfsstream": "^1.6",
"mockery/mockery": "^1.6",
"orchestra/testbench": "^9.0",
"orchestra/testbench": "^10.0",
"php-mock/php-mock-phpunit": "^2.13",
"phpstan/phpstan": "^2.1",
"phpunit/phpunit": "^12.0",
+20 -3
View File
@@ -84,8 +84,25 @@ $api = new Api('YOUR_BOT_API_TOKEN');
Так же вы можете создать экземпляр бота гибко настроив все зависимости под свои нужды.
```php
$guzzle = new \GuzzleHttp\Client([
'timeout' => 10,
'connect_timeout' => 5,
'read_timeout' => 10,
'headers' => ['User-Agent' => 'max-bot-api-client-php'],
// 'verify' => false, либо путь до сертификата '/path/to/cert.pem'
]);
$httpFactory = new \GuzzleHttp\Psr7\HttpFactory();
$client = new \BushlanovDev\MaxMessengerBot\Client(
$accessToken,
$guzzle,
$httpFactory,
$httpFactory,
'https://platform-api2.max.ru',
);
$api = new Api(
client: new Client(...),
accessToken: 'YOUR_BOT_API_TOKEN',
client: $client,
modelFactory: new ModelFactory(),
logger: new YourPsrLogger(),
);
@@ -275,11 +292,11 @@ $subscriptions = $api->getSubscriptions();
Подписывает бота на получение обновлений через WebHook.
После вызова этого метода бот будет получать уведомления о новых событиях в чатах на указанный URL.
Ваш сервер должен прослушивать один из следующих портов: 80, 8080, 443, 8443, 16384-32383.
Судя по обновленной [документации](https://dev.max.ru/docs-api/methods/POST/subscriptions) поддерживается только 443 порт!
```php
$api->subscribe(
url: 'https://example.com/webhook', // URL на который будут приходить хуки. Должен начинаться с http(s)://
url: 'https://example.com/webhook', // HTTPS URL на который будут приходить хуки. Должен начинаться с https://
secret: 'super_secret', // Секретная фраза для проверки хуков (необязательно)
updateTypes: [UpdateType::MessageCreated], // Типы хуков которые вы хотите получать (либо ничего не указывать, чтобы получать все)
);
+2 -2
View File
@@ -48,11 +48,11 @@ use RuntimeException;
*/
class Api
{
public const string LIBRARY_VERSION = '1.5.1';
public const string LIBRARY_VERSION = '1.6.4';
public const string API_VERSION = '1.2.5';
private const string API_BASE_URL = 'https://platform-api.max.ru';
private const string API_BASE_URL = 'https://platform-api2.max.ru';
private const string METHOD_GET = 'GET';
private const string METHOD_POST = 'POST';
-2
View File
@@ -13,8 +13,6 @@ enum AttachmentType: string
case Sticker = 'sticker';
case Contact = 'contact';
case InlineKeyboard = 'inline_keyboard';
case ReplyKeyboard = 'reply_keyboard';
case Location = 'location';
case Share = 'share';
case Data = 'data';
}
+4
View File
@@ -15,5 +15,9 @@ enum ChatAdminPermission: string
case ChangeChatInfo = 'change_chat_info';
case PinMessage = 'pin_message';
case Write = 'write';
case CanCall = 'can_call';
case EditLink = 'edit_link';
case PostEditDeleteMessage = 'post_edit_delete_message';
case EditMessage = 'edit_message';
case DeleteMessage = 'delete_message';
}
+1
View File
@@ -13,4 +13,5 @@ enum InlineButtonType: string
case OpenApp = 'open_app';
case Message = 'message';
case Chat = 'chat';
case Clipboard = 'clipboard';
}
+3 -13
View File
@@ -14,6 +14,7 @@ use BushlanovDev\MaxMessengerBot\Models\Attachments\AudioAttachment;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Inline\AbstractInlineButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Inline\CallbackButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Inline\ChatButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Inline\ClipboardButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Inline\LinkButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Inline\MessageButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Inline\OpenAppButton;
@@ -24,12 +25,10 @@ use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Reply\SendContactBut
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Reply\SendGeoLocationButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Reply\SendMessageButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\ContactAttachment;
use BushlanovDev\MaxMessengerBot\Models\Attachments\DataAttachment;
use BushlanovDev\MaxMessengerBot\Models\Attachments\FileAttachment;
use BushlanovDev\MaxMessengerBot\Models\Attachments\InlineKeyboardAttachment;
use BushlanovDev\MaxMessengerBot\Models\Attachments\LocationAttachment;
use BushlanovDev\MaxMessengerBot\Models\Attachments\PhotoAttachment;
use BushlanovDev\MaxMessengerBot\Models\Attachments\ReplyKeyboardAttachment;
use BushlanovDev\MaxMessengerBot\Models\Attachments\ShareAttachment;
use BushlanovDev\MaxMessengerBot\Models\Attachments\StickerAttachment;
use BushlanovDev\MaxMessengerBot\Models\Attachments\VideoAttachment;
@@ -242,14 +241,6 @@ readonly class ModelFactory
public function createAttachment(array $data): AbstractAttachment
{
$attachmentType = AttachmentType::tryFrom($data['type'] ?? '');
if ($attachmentType === AttachmentType::ReplyKeyboard
&& isset($data['buttons']) && is_array($data['buttons'])) {
$data['buttons'] = array_map(
fn($rowOfButtons) => array_map([$this, 'createReplyButton'], $rowOfButtons),
$data['buttons'],
);
}
if ($attachmentType === AttachmentType::InlineKeyboard
&& isset($data['payload']['buttons']) && is_array($data['payload']['buttons'])) {
$data['payload']['buttons'] = array_map(
@@ -259,8 +250,6 @@ readonly class ModelFactory
}
return match ($attachmentType) {
AttachmentType::Data => DataAttachment::fromArray($data),
AttachmentType::Share => ShareAttachment::fromArray($data),
AttachmentType::Image => PhotoAttachment::fromArray($data),
AttachmentType::Video => VideoAttachment::fromArray($data),
AttachmentType::Audio => AudioAttachment::fromArray($data),
@@ -268,8 +257,8 @@ readonly class ModelFactory
AttachmentType::Sticker => StickerAttachment::fromArray($data),
AttachmentType::Contact => ContactAttachment::fromArray($data),
AttachmentType::InlineKeyboard => InlineKeyboardAttachment::fromArray($data),
AttachmentType::ReplyKeyboard => ReplyKeyboardAttachment::fromArray($data),
AttachmentType::Location => LocationAttachment::fromArray($data),
AttachmentType::Share => ShareAttachment::fromArray($data),
default => throw new LogicException('Unknown or unsupported attachment type: ' . ($data['type'] ?? 'none')),
};
}
@@ -312,6 +301,7 @@ readonly class ModelFactory
InlineButtonType::RequestGeoLocation => RequestGeoLocationButton::fromArray($data),
InlineButtonType::Chat => ChatButton::fromArray($data),
InlineButtonType::OpenApp => OpenAppButton::fromArray($data),
InlineButtonType::Clipboard => ClipboardButton::fromArray($data),
InlineButtonType::Message => MessageButton::fromArray($data),
default => throw new LogicException(
'Unknown or unsupported inline button type: ' . ($data['type'] ?? 'none')
@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Inline;
use BushlanovDev\MaxMessengerBot\Enums\InlineButtonType;
/**
* A button that, when clicked, copies text to the clipboard.
*/
final readonly class ClipboardButton extends AbstractInlineButton
{
public ?string $payload;
/**
* @param string $text Visible button text (1 to 128 characters).
* @param string $payload Text which will be copied.
*/
public function __construct(string $text, string $payload)
{
parent::__construct(InlineButtonType::Clipboard, $text);
$this->payload = $payload;
}
}
-21
View File
@@ -1,21 +0,0 @@
<?php
declare(strict_types=1);
namespace BushlanovDev\MaxMessengerBot\Models\Attachments;
use BushlanovDev\MaxMessengerBot\Enums\AttachmentType;
/**
* Represents an attachment containing a payload from a SendMessageButton.
*/
final readonly class DataAttachment extends AbstractAttachment
{
/**
* @param string $data The payload from the button.
*/
public function __construct(public string $data)
{
parent::__construct(AttachmentType::Data);
}
}
@@ -1,22 +0,0 @@
<?php
declare(strict_types=1);
namespace BushlanovDev\MaxMessengerBot\Models\Attachments\Payloads;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Reply\AbstractReplyButton;
final readonly class ReplyKeyboardAttachmentRequestPayload extends AbstractAttachmentRequestPayload
{
/**
* @param AbstractReplyButton[][] $buttons Two-dimensional array of buttons.
* @param bool $direct Applicable only for chats.
* @param int|null $directUserId If set, reply keyboard will only be shown to this participant.
*/
public function __construct(
public array $buttons,
public bool $direct = false,
public ?int $directUserId = null,
) {
}
}
@@ -1,19 +0,0 @@
<?php
declare(strict_types=1);
namespace BushlanovDev\MaxMessengerBot\Models\Attachments;
use BushlanovDev\MaxMessengerBot\Enums\AttachmentType;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Reply\AbstractReplyButton;
final readonly class ReplyKeyboardAttachment extends AbstractAttachment
{
/**
* @param AbstractReplyButton[][] $buttons
*/
public function __construct(public array $buttons)
{
parent::__construct(AttachmentType::ReplyKeyboard);
}
}
@@ -1,28 +0,0 @@
<?php
declare(strict_types=1);
namespace BushlanovDev\MaxMessengerBot\Models\Attachments\Requests;
use BushlanovDev\MaxMessengerBot\Enums\AttachmentType;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Reply\AbstractReplyButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Payloads\ReplyKeyboardAttachmentRequestPayload;
final readonly class ReplyKeyboardAttachmentRequest extends AbstractAttachmentRequest
{
/**
* @param AbstractReplyButton[][] $buttons
* @param bool $direct
* @param int|null $directUserId
*/
public function __construct(
array $buttons,
bool $direct = false,
?int $directUserId = null
) {
parent::__construct(
AttachmentType::ReplyKeyboard,
new ReplyKeyboardAttachmentRequestPayload($buttons, $direct, $directUserId),
);
}
}
+2
View File
@@ -10,6 +10,7 @@ use BushlanovDev\MaxMessengerBot\LongPollingHandler;
use BushlanovDev\MaxMessengerBot\ModelFactory;
use BushlanovDev\MaxMessengerBot\UpdateDispatcher;
use BushlanovDev\MaxMessengerBot\WebhookHandler;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\UsesClass;
@@ -19,6 +20,7 @@ use Psr\Log\LoggerInterface;
use ReflectionClass;
#[CoversClass(Api::class)]
#[AllowMockObjectsWithoutExpectations]
#[UsesClass(UpdateDispatcher::class)]
#[UsesClass(WebhookHandler::class)]
#[UsesClass(LongPollingHandler::class)]
+4
View File
@@ -62,6 +62,7 @@ use InvalidArgumentException;
use LogicException;
use org\bovigo\vfs\vfsStream;
use phpmock\phpunit\PHPMock;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\PreserveGlobalState;
use PHPUnit\Framework\Attributes\RunInSeparateProcess;
@@ -75,6 +76,7 @@ use ReflectionClass;
use RuntimeException;
#[CoversClass(Api::class)]
#[AllowMockObjectsWithoutExpectations]
#[UsesClass(Result::class)]
#[UsesClass(Client::class)]
#[UsesClass(BotInfo::class)]
@@ -1667,12 +1669,14 @@ final class ApiTest extends TestCase
$admins = [
new ChatAdmin(101, [ChatAdminPermission::Write]),
new ChatAdmin(202, [ChatAdminPermission::PinMessage]),
new ChatAdmin(303, [ChatAdminPermission::EditMessage, ChatAdminPermission::CanCall], 'SuperUser'),
];
$expectedBody = [
'admins' => [
['user_id' => 101, 'permissions' => ['write'], 'alias' => null],
['user_id' => 202, 'permissions' => ['pin_message'], 'alias' => null],
['user_id' => 303, 'permissions' => ['edit_message', 'can_call'], 'alias' => 'SuperUser'],
],
];
$rawResponse = ['success' => true];
+2
View File
@@ -16,6 +16,7 @@ use BushlanovDev\MaxMessengerBot\Exceptions\SerializationException;
use BushlanovDev\MaxMessengerBot\Exceptions\UnauthorizedException;
use GuzzleHttp\Psr7\HttpFactory;
use InvalidArgumentException;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
@@ -32,6 +33,7 @@ use Psr\Http\Message\StreamInterface;
use Psr\Log\LoggerInterface;
#[CoversClass(Client::class)]
#[AllowMockObjectsWithoutExpectations]
final class ClientTest extends TestCase
{
private const string FAKE_TOKEN = '12345:abcdef';
@@ -7,6 +7,7 @@ namespace BushlanovDev\MaxMessengerBot\Tests\Laravel\Commands;
use BushlanovDev\MaxMessengerBot\Laravel\Commands\PollingStartCommand;
use BushlanovDev\MaxMessengerBot\Laravel\MaxBotManager;
use Illuminate\Support\Facades\Log;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\UsesClass;
@@ -15,6 +16,7 @@ use Symfony\Component\Console\Application as ConsoleApplication;
use Symfony\Component\Console\Tester\CommandTester;
#[CoversClass(PollingStartCommand::class)]
#[AllowMockObjectsWithoutExpectations]
#[UsesClass(MaxBotManager::class)]
final class PollingStartCommandTest extends TestCase
{
@@ -9,6 +9,7 @@ use BushlanovDev\MaxMessengerBot\Enums\UpdateType;
use BushlanovDev\MaxMessengerBot\Laravel\Commands\WebhookListCommand;
use BushlanovDev\MaxMessengerBot\Models\Subscription;
use Illuminate\Support\Facades\Log;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\UsesClass;
@@ -17,6 +18,7 @@ use Symfony\Component\Console\Application as ConsoleApplication;
use Symfony\Component\Console\Tester\CommandTester;
#[CoversClass(WebhookListCommand::class)]
#[AllowMockObjectsWithoutExpectations]
#[UsesClass(Api::class)]
#[UsesClass(Subscription::class)]
final class WebhookListCommandTest extends TestCase
@@ -10,6 +10,7 @@ use BushlanovDev\MaxMessengerBot\Laravel\Commands\WebhookSubscribeCommand;
use BushlanovDev\MaxMessengerBot\Models\Result;
use Illuminate\Contracts\Config\Repository as Config;
use Illuminate\Support\Facades\Log;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\UsesClass;
@@ -18,6 +19,7 @@ use Symfony\Component\Console\Application as ConsoleApplication;
use Symfony\Component\Console\Tester\CommandTester;
#[CoversClass(WebhookSubscribeCommand::class)]
#[AllowMockObjectsWithoutExpectations]
#[UsesClass(Api::class)]
#[UsesClass(Result::class)]
final class WebhookSubscribeCommandTest extends TestCase
@@ -8,6 +8,7 @@ use BushlanovDev\MaxMessengerBot\Api;
use BushlanovDev\MaxMessengerBot\Laravel\Commands\WebhookUnsubscribeCommand;
use BushlanovDev\MaxMessengerBot\Models\Result;
use Illuminate\Support\Facades\Log;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\UsesClass;
@@ -16,6 +17,7 @@ use Symfony\Component\Console\Application as ConsoleApplication;
use Symfony\Component\Console\Tester\CommandTester;
#[CoversClass(WebhookUnsubscribeCommand::class)]
#[AllowMockObjectsWithoutExpectations]
#[UsesClass(Api::class)]
#[UsesClass(Result::class)]
final class WebhookUnsubscribeCommandTest extends TestCase
+2
View File
@@ -20,6 +20,7 @@ use Illuminate\Container\Container;
use Illuminate\Contracts\Config\Repository;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Facade;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\UsesClass;
@@ -28,6 +29,7 @@ use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
#[CoversClass(MaxBotManager::class)]
#[AllowMockObjectsWithoutExpectations]
#[UsesClass(Message::class)]
#[UsesClass(MessageBody::class)]
#[UsesClass(Recipient::class)]
@@ -22,6 +22,7 @@ use InvalidArgumentException;
use LogicException;
use Orchestra\Testbench\TestCase;
use phpmock\phpunit\PHPMock;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\PreserveGlobalState;
@@ -33,6 +34,7 @@ use Psr\Log\NullLogger;
use ReflectionClass;
#[CoversClass(MaxBotServiceProvider::class)]
#[AllowMockObjectsWithoutExpectations]
#[UsesClass(Api::class)]
#[UsesClass(Client::class)]
#[UsesClass(UpdateDispatcher::class)]
+2
View File
@@ -16,6 +16,7 @@ use BushlanovDev\MaxMessengerBot\UpdateDispatcher;
use Error;
use Exception;
use phpmock\phpunit\PHPMock;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\PreserveGlobalState;
@@ -26,6 +27,7 @@ use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
#[CoversClass(LongPollingHandler::class)]
#[AllowMockObjectsWithoutExpectations]
#[UsesClass(UpdateDispatcher::class)]
#[UsesClass(UpdateList::class)]
#[UsesClass(AbstractUpdate::class)]
+5 -41
View File
@@ -18,7 +18,6 @@ use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Inline\RequestGeoLoc
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Reply\AbstractReplyButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Reply\SendContactButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Reply\SendMessageButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\DataAttachment;
use BushlanovDev\MaxMessengerBot\Models\Attachments\InlineKeyboardAttachment;
use BushlanovDev\MaxMessengerBot\Models\Attachments\LocationAttachment;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Payloads\KeyboardPayload;
@@ -26,7 +25,6 @@ use BushlanovDev\MaxMessengerBot\Models\Attachments\Payloads\PhotoAttachmentPayl
use BushlanovDev\MaxMessengerBot\Models\Attachments\Payloads\PhotoAttachmentRequestPayload;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Payloads\ShareAttachmentRequestPayload;
use BushlanovDev\MaxMessengerBot\Models\Attachments\PhotoAttachment;
use BushlanovDev\MaxMessengerBot\Models\Attachments\ReplyKeyboardAttachment;
use BushlanovDev\MaxMessengerBot\Models\Attachments\ShareAttachment;
use BushlanovDev\MaxMessengerBot\Models\BotCommand;
use BushlanovDev\MaxMessengerBot\Models\BotInfo;
@@ -85,7 +83,6 @@ use Psr\Log\LoggerInterface;
#[UsesClass(PhotoAttachmentRequestPayload::class)]
#[UsesClass(VideoUrls::class)]
#[UsesClass(AbstractAttachment::class)]
#[UsesClass(DataAttachment::class)]
#[UsesClass(ShareAttachment::class)]
#[UsesClass(ShareAttachmentRequestPayload::class)]
#[UsesClass(LinkMarkup::class)]
@@ -96,7 +93,6 @@ use Psr\Log\LoggerInterface;
#[UsesClass(AbstractReplyButton::class)]
#[UsesClass(SendContactButton::class)]
#[UsesClass(SendMessageButton::class)]
#[UsesClass(ReplyKeyboardAttachment::class)]
#[UsesClass(AbstractInlineButton::class)]
#[UsesClass(ChatButton::class)]
#[UsesClass(RequestContactButton::class)]
@@ -593,7 +589,6 @@ final class ModelFactoryTest extends TestCase
'seq' => 102,
'text' => 'Message with data attachment',
'attachments' => [
['type' => 'data', 'data' => 'payload_from_reply_button'],
[
'type' => 'share',
'payload' => ['url' => 'http://a.com'],
@@ -615,16 +610,13 @@ final class ModelFactoryTest extends TestCase
$this->assertInstanceOf(Message::class, $message);
$this->assertInstanceOf(MessageBody::class, $message->body);
$this->assertIsArray($attachments);
$this->assertCount(3, $attachments);
$this->assertCount(2, $attachments);
$this->assertInstanceOf(DataAttachment::class, $attachments[0]);
$this->assertSame('payload_from_reply_button', $attachments[0]->data);
$this->assertInstanceOf(ShareAttachment::class, $message->body->attachments[0]);
$this->assertSame('Test Share', $attachments[0]->title);
$this->assertInstanceOf(ShareAttachment::class, $message->body->attachments[1]);
$this->assertSame('Test Share', $attachments[1]->title);
$this->assertInstanceOf(PhotoAttachment::class, $attachments[2]);
$this->assertSame(1, $attachments[2]->payload->photoId);
$this->assertInstanceOf(PhotoAttachment::class, $attachments[1]);
$this->assertSame(1, $attachments[1]->payload->photoId);
}
#[Test]
@@ -665,26 +657,6 @@ final class ModelFactoryTest extends TestCase
$this->factory->createMarkupElement(['type' => 'brand_new_unsupported_type']);
}
#[Test]
public function createAttachmentCorrectlyHydratesReplyKeyboard(): void
{
$data = [
'type' => 'reply_keyboard',
'buttons' => [
[['type' => 'message', 'text' => 'Hello']],
[['type' => 'user_contact', 'text' => 'My Contact']]
]
];
$attachment = $this->factory->createAttachment($data);
$this->assertInstanceOf(ReplyKeyboardAttachment::class, $attachment);
$this->assertCount(2, $attachment->buttons);
$this->assertInstanceOf(SendMessageButton::class, $attachment->buttons[0][0]);
$this->assertInstanceOf(SendContactButton::class, $attachment->buttons[1][0]);
$this->assertSame('My Contact', $attachment->buttons[1][0]->text);
}
#[Test]
public function createReplyButtonThrowsExceptionForUnknownType(): void
{
@@ -769,14 +741,6 @@ final class ModelFactoryTest extends TestCase
public static function attachmentTypeProvider(): array
{
return [
'Data Attachment' => [
['type' => 'data', 'data' => 'test_payload'],
DataAttachment::class,
function (TestCase $test, DataAttachment $attachment) {
$test->assertSame('test_payload', $attachment->data);
}
],
'Location Attachment' => [
['type' => 'location', 'latitude' => 55.751244, 'longitude' => 37.618423],
LocationAttachment::class,
@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace BushlanovDev\MaxMessengerBot\Tests\Models\Attachments\Buttons\Inline;
use BushlanovDev\MaxMessengerBot\Enums\InlineButtonType;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Inline\ClipboardButton;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
#[CoversClass(ClipboardButton::class)]
final class ClipboardButtonTest extends TestCase
{
#[Test]
public function toArraySerializesCorrectly(): void
{
$button = new ClipboardButton('display', 'copy');
$expectedArray = [
'payload' => 'copy',
'type' => InlineButtonType::Clipboard->value,
'text' => 'display',
];
$resultArray = $button->toArray();
$this->assertSame($expectedArray, $resultArray);
}
#[Test]
public function fromArrayHydratesCorrectly(): void
{
$data = [
'type' => 'clipboard',
'text' => 'display',
'payload' => 'copy'
];
$button = ClipboardButton::fromArray($data);
$this->assertInstanceOf(ClipboardButton::class, $button);
$this->assertSame(InlineButtonType::Clipboard, $button->type);
$this->assertSame('display', $button->text);
$this->assertSame('copy', $button->payload);
}
}
@@ -1,49 +0,0 @@
<?php
declare(strict_types=1);
namespace BushlanovDev\MaxMessengerBot\Tests\Models\Attachments;
use BushlanovDev\MaxMessengerBot\Enums\AttachmentType;
use BushlanovDev\MaxMessengerBot\Models\Attachments\AbstractAttachment;
use BushlanovDev\MaxMessengerBot\Models\Attachments\DataAttachment;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\UsesClass;
use PHPUnit\Framework\TestCase;
#[CoversClass(DataAttachment::class)]
#[UsesClass(AbstractAttachment::class)]
final class DataAttachmentTest extends TestCase
{
#[Test]
public function canBeCreatedAndSerialized(): void
{
$attachment = new DataAttachment('some_payload_from_button');
$this->assertSame(AttachmentType::Data, $attachment->type);
$this->assertSame('some_payload_from_button', $attachment->data);
$expectedArray = [
'type' => 'data',
'data' => 'some_payload_from_button',
];
$this->assertEquals($expectedArray, $attachment->toArray());
}
#[Test]
public function canBeCreatedFromArray(): void
{
$data = [
'type' => 'data',
'data' => 'payload123',
];
$attachment = DataAttachment::fromArray($data);
$this->assertInstanceOf(DataAttachment::class, $attachment);
$this->assertSame(AttachmentType::Data, $attachment->type);
$this->assertSame('payload123', $attachment->data);
}
}
@@ -1,99 +0,0 @@
<?php
declare(strict_types=1);
namespace BushlanovDev\MaxMessengerBot\Tests\Models\Attachments\Payloads;
use BushlanovDev\MaxMessengerBot\Enums\Intent;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Reply\SendContactButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Reply\SendMessageButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Payloads\ReplyKeyboardAttachmentRequestPayload;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\UsesClass;
use PHPUnit\Framework\TestCase;
#[CoversClass(ReplyKeyboardAttachmentRequestPayload::class)]
#[UsesClass(SendMessageButton::class)]
#[UsesClass(SendContactButton::class)]
final class ReplyKeyboardAttachmentRequestPayloadTest extends TestCase
{
#[Test]
public function toArrayWithDefaults(): void
{
$buttons = [
[new SendMessageButton('Help')],
[new SendContactButton('Share Contact')],
];
$payload = new ReplyKeyboardAttachmentRequestPayload($buttons);
$expected = [
'buttons' => [
[
[
'type' => 'message',
'text' => 'Help',
'payload' => null,
'intent' => 'default',
],
],
[
[
'type' => 'user_contact',
'text' => 'Share Contact',
],
],
],
'direct' => false,
'direct_user_id' => null,
];
$this->assertEquals($expected, $payload->toArray());
}
#[Test]
public function toArrayWithAllParameters(): void
{
$buttons = [
[new SendMessageButton('Confirm', 'confirm-action', Intent::Positive)],
];
$payload = new ReplyKeyboardAttachmentRequestPayload(
buttons: $buttons,
direct: true,
directUserId: 987654321,
);
$expected = [
'buttons' => [
[
[
'type' => 'message',
'text' => 'Confirm',
'payload' => 'confirm-action',
'intent' => 'positive',
],
],
],
'direct' => true,
'direct_user_id' => 987654321,
];
$this->assertEquals($expected, $payload->toArray());
}
#[Test]
public function toArrayWithEmptyButtons(): void
{
$payload = new ReplyKeyboardAttachmentRequestPayload(buttons: []);
$expected = [
'buttons' => [],
'direct' => false,
'direct_user_id' => null,
];
$this->assertEquals($expected, $payload->toArray());
}
}
@@ -1,43 +0,0 @@
<?php
declare(strict_types=1);
namespace BushlanovDev\MaxMessengerBot\Tests\Models\Attachments;
use BushlanovDev\MaxMessengerBot\ModelFactory;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Reply\AbstractReplyButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Reply\SendContactButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Reply\SendMessageButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\ReplyKeyboardAttachment;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\UsesClass;
use PHPUnit\Framework\TestCase;
#[CoversClass(ReplyKeyboardAttachment::class)]
#[UsesClass(AbstractReplyButton::class)]
#[UsesClass(SendContactButton::class)]
#[UsesClass(SendMessageButton::class)]
#[UsesClass(ModelFactory::class)]
final class ReplyKeyboardAttachmentTest extends TestCase
{
#[Test]
public function canBeCreatedFromArrayViaFactory(): void
{
$data = [
'type' => 'reply_keyboard',
'buttons' => [
[['type' => 'message', 'text' => 'Hello']],
[['type' => 'user_contact', 'text' => 'My Contact']]
]
];
$factory = new ModelFactory();
$attachment = $factory->createAttachment($data);
$this->assertInstanceOf(ReplyKeyboardAttachment::class, $attachment);
$this->assertCount(2, $attachment->buttons);
$this->assertInstanceOf(SendContactButton::class, $attachment->buttons[1][0]);
$this->assertSame('My Contact', $attachment->buttons[1][0]->text);
}
}
@@ -1,59 +0,0 @@
<?php
declare(strict_types=1);
namespace BushlanovDev\MaxMessengerBot\Tests\Models\Attachments\Requests;
use BushlanovDev\MaxMessengerBot\Enums\Intent;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Reply\SendContactButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Buttons\Reply\SendMessageButton;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Payloads\ReplyKeyboardAttachmentRequestPayload;
use BushlanovDev\MaxMessengerBot\Models\Attachments\Requests\ReplyKeyboardAttachmentRequest;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\UsesClass;
use PHPUnit\Framework\TestCase;
#[CoversClass(ReplyKeyboardAttachmentRequest::class)]
#[UsesClass(SendMessageButton::class)]
#[UsesClass(SendContactButton::class)]
#[UsesClass(ReplyKeyboardAttachmentRequestPayload::class)]
final class ReplyKeyboardAttachmentRequestTest extends TestCase
{
#[Test]
public function toArray(): void
{
$buttons = [
[new SendMessageButton('Help', 'help_payload', Intent::Positive)],
[new SendContactButton('Share Contact')],
];
$request = new ReplyKeyboardAttachmentRequest(buttons: $buttons, direct: true);
$expectedArray = [
'type' => 'reply_keyboard',
'payload' => [
'buttons' => [
[
[
'type' => 'message',
'text' => 'Help',
'payload' => 'help_payload',
'intent' => 'positive',
],
],
[
[
'type' => 'user_contact',
'text' => 'Share Contact',
],
],
],
'direct' => true,
'direct_user_id' => null,
],
];
$this->assertEquals($expectedArray, $request->toArray());
}
}
+2
View File
@@ -14,12 +14,14 @@ use BushlanovDev\MaxMessengerBot\Models\Updates\BotStartedUpdate;
use BushlanovDev\MaxMessengerBot\Models\Updates\MessageCreatedUpdate;
use BushlanovDev\MaxMessengerBot\Models\UserWithPhoto;
use BushlanovDev\MaxMessengerBot\UpdateDispatcher;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\UsesClass;
use PHPUnit\Framework\TestCase;
#[CoversClass(UpdateDispatcher::class)]
#[AllowMockObjectsWithoutExpectations]
#[UsesClass(UserWithPhoto::class)]
#[UsesClass(BotStartedUpdate::class)]
#[UsesClass(Message::class)]
+2
View File
@@ -19,6 +19,7 @@ use BushlanovDev\MaxMessengerBot\UpdateDispatcher;
use BushlanovDev\MaxMessengerBot\WebhookHandler;
use LogicException;
use phpmock\phpunit\PHPMock;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\PreserveGlobalState;
@@ -32,6 +33,7 @@ use Psr\Http\Message\StreamInterface;
use Psr\Log\LoggerInterface;
#[CoversClass(WebhookHandler::class)]
#[AllowMockObjectsWithoutExpectations]
#[UsesClass(UpdateDispatcher::class)]
#[UsesClass(Message::class)]
#[UsesClass(MessageBody::class)]