Перейти к содержимому

Маршрутизация с PHP атрибутами

PHP атрибуты предоставляют чистую, основанную на декораторах альтернативу определению маршрутов с использованием фасада TelegramRouter. Этот подход размещает определения маршрутов близко к методам-обработчикам, улучшая организацию и читаемость кода.

Вместо регистрации маршрутов через фасад:

TelegramRouter::onCommand('/start', function(CommandData $data) {
// Обработка команды /start
});

Вы можете определять маршруты, используя атрибуты прямо на методах контроллера:

#[OnCommand('/start')]
public function handleStart(CommandData $data) {
// Обработка команды /start
}

Создайте класс контроллера и украсьте методы атрибутами маршрутизации:

<?php
namespace App\Telegram\Handlers;
use HybridGram\Core\Routing\Attributes\OnCommand;
use HybridGram\Core\Routing\Attributes\OnTextMessage;
use HybridGram\Core\Routing\RouteData\CommandData;
use HybridGram\Core\Routing\RouteData\TextMessageData;
class BotHandler
{
#[OnCommand('/start')]
public function handleStart(CommandData $data): void
{
$telegram = app(\HybridGram\Telegram\TelegramBotApi::class);
$telegram->sendMessage($data->getChat()->id, 'Добро пожаловать!');
}
#[OnTextMessage]
public function handleMessage(TextMessageData $data): void
{
// Обработка всех текстовых сообщений
}
}

Маршруты, определённые с атрибутами, автоматически обнаруживаются и регистрируются при загрузке приложения. Фреймворк сканирует классы приложения и регистрирует любые маршруты, определённые с помощью атрибутов маршрутизации.

Чтобы включить маршрутизацию на основе атрибутов, убедитесь, что AttributeRouteRegistrar вызывается в поставщике услуг или файле загрузки приложения.

Обработка текстовых сообщений:

#[OnTextMessage]
public function handleMessage(TextMessageData $data): void {
// Обработка всех текстовых сообщений
}
#[OnTextMessage(pattern: 'привет')]
public function handleGreeting(TextMessageData $data): void {
// Обработка сообщений содержащих 'привет'
}

Обработка команд Telegram:

#[OnCommand('/start')]
public function handleStart(CommandData $data): void {
// Обработка команды /start
}
#[OnCommand('/user:*')]
public function handleUserCommand(CommandData $data): void {
// Обработка /user:* с параметрами
}

Обработка нажатий на кнопки:

#[OnCallbackQuery(pattern: 'menu:*')]
public function handleMenuCallback(CallbackQueryData $data): void {
// Обработка callback запросов типа 'menu:home'
}

Обработка различных типов медиа:

#[OnPhoto]
public function handlePhoto(PhotoData $data): void {}
#[OnDocument]
public function handleDocument(DocumentData $data): void {}
#[OnAudio]
public function handleAudio(AudioData $data): void {}
#[OnVideo]
public function handleVideo(VideoData $data): void {}
#[OnVoice]
public function handleVoice(VoiceData $data): void {}
#[OnLocation]
public function handleLocation(LocationData $data): void {}
#[OnContact]
public function handleContact(ContactData $data): void {}
#[OnChatMember]
public function handleChatMember(ChatMemberUpdatedData $data): void {}
#[OnMyChatMember]
public function handleBotChatMember(ChatMemberUpdatedData $data): void {}
#[OnPoll]
public function handlePoll(PollData $data): void {}
#[OnInlineQuery]
public function handleInlineQuery(InlineQueryData $data): void {}
#[OnAny]
public function handleAny(UpdateData $data): void {}
#[OnFallback]
public function handleFallback(FallbackData $data): void {}

Ограничьте маршруты определённой типа чатов:

use HybridGram\Core\Routing\Attributes\ChatTypes;
use HybridGram\Core\Routing\ChatType;
#[OnCommand('/admin')]
#[ChatTypes([ChatType::PRIVATE, ChatType::GROUP])]
public function handleAdminCommand(CommandData $data): void {
// Работает только в приватных чатах и группах
}

Нацельтесь на конкретные боты:

use HybridGram\Core\Routing\Attributes\ForBot;
#[OnCommand('/start')]
#[ForBot('main')]
public function handleStart(CommandData $data): void {
// Только для бота 'main'
}

Применяйте middleware к маршрутам:

use HybridGram\Core\Routing\Attributes\TgMiddlewares;
use App\Telegram\Middleware\AuthMiddleware;
#[OnCommand('/admin')]
#[TgMiddlewares([AuthMiddleware::class])]
public function handleAdmin(CommandData $data): void {
// AuthMiddleware выполняется перед этим обработчиком
}

Маршрутизация на основе состояния пользователя

Заголовок раздела «Маршрутизация на основе состояния пользователя»

Маршрутизируйте в зависимости от состояния пользователя:

use HybridGram\Core\Routing\Attributes\FromUserState;
use HybridGram\Core\Routing\Attributes\ToUserState;
#[OnTextMessage]
#[FromUserState('waiting_name')]
#[ToUserState('name_received')]
public function handleNameInput(TextMessageData $data): void {
// Обрабатывает только если пользователь в состоянии 'waiting_name'
// Переходит в состояние 'name_received' после выполнения
}

Маршрутизируйте на основе состояния чата:

use HybridGram\Core\Routing\Attributes\FromChatState;
use HybridGram\Core\Routing\Attributes\ToChatState;
#[OnTextMessage]
#[FromChatState('setup_mode')]
public function handleSetup(TextMessageData $data): void {
// Только когда чат в режиме 'setup_mode'
}

Вы можете комбинировать несколько атрибутов на одном методе:

#[OnTextMessage(pattern: 'price:*')]
#[ForBot('main')]
#[ChatTypes([ChatType::PRIVATE])]
#[FromUserState('shopping')]
public function handlePriceQuery(TextMessageData $data): void {
// Этот обработчик срабатывает только когда ВСЕ условия выполнены:
// - Текст сообщения содержит шаблон 'price:*'
// - Бот 'main'
// - Чат приватный
// - Пользователь в состоянии 'shopping'
}

Группируйте связанные обработчики в выделённых классах контроллера:

<?php
namespace App\Telegram\Handlers;
class CommandHandler
{
#[OnCommand('/start')]
public function handleStart(CommandData $data): void {}
#[OnCommand('/help')]
public function handleHelp(CommandData $data): void {}
}
class MessageHandler
{
#[OnTextMessage]
public function handleMessage(TextMessageData $data): void {}
}

Убедитесь, что ваши классы обработчиков находятся в доступных местоположениях. По умолчанию фреймворк сканирует:

  • app/Telegram/
  • app/Handlers/

Если нужно, сконфигурируйте дополнительные пути.

Всегда добавляйте тип параметру данных:

// ✅ Хорошо - типы предотвращают ошибки
#[OnCommand('/start')]
public function handleStart(CommandData $data): void {}
// ❌ Избегайте - теряется безопасность типов
#[OnCommand('/start')]
public function handleStart($data): void {}

Маршрутизация через фасад (традиционный способ)

Заголовок раздела «Маршрутизация через фасад (традиционный способ)»
routes/telegram.php
TelegramRouter::onCommand('/start', function(CommandData $data) {
// ...
});
TelegramRouter::onTextMessage(function(TextMessageData $data) {
// ...
});

Маршрутизация через атрибуты (современный способ)

Заголовок раздела «Маршрутизация через атрибуты (современный способ)»
app/Telegram/BotHandler.php
class BotHandler
{
#[OnCommand('/start')]
public function handleStart(CommandData $data): void {
// ...
}
#[OnTextMessage]
public function handleMessage(TextMessageData $data): void {
// ...
}
}

Оба подхода работают одинаково хорошо. Выбирайте в зависимости от предпочтений вашего проекта:

  • Атрибуты: Лучше для больших проектов с множеством обработчиков
  • Фасад: Лучше для небольших проектов или когда все маршруты в одном месте

Вы можете создавать пользовательские атрибуты, расширяющие TelegramRouteAttribute:

use HybridGram\Core\Routing\Attributes\TelegramRouteAttribute;
use HybridGram\Core\Routing\TelegramRouteBuilder;
#[Attribute(Attribute::TARGET_METHOD)]
final class OnVIP implements TelegramRouteAttribute
{
public function registerRoute(TelegramRouteBuilder $builder, \Closure|string|array $action): void
{
// Пользовательская логика регистрации
$builder->onTextMessage($action)
->middleware(VIPCheckMiddleware::class);
}
}

В production маршруты атрибутов кешируются для лучшей производительности. Запустите:

Окно терминала
php artisan config:cache

Чтобы очистить кеш во время разработки, используйте:

Окно терминала
php artisan config:clear