Installation:
composer require boshurik/telegram-bot-bundle
Ensure TELEGRAM_BOT_TOKEN (or FIRST_TELEGRAM_BOT_API_TOKEN for multiple bots) is set in your .env.
Register the Bundle:
Add to config/bundles.php (Symfony 5+):
BoShurik\TelegramBotBundle\BoShurikTelegramBotBundle::class => ['all' => true],
Configure Routing:
Add to config/routes.yaml:
BoShurikTelegramBotBundle:
resource: "@BoShurikTelegramBotBundle/Resources/config/routing.php"
prefix: /_telegram/%env(TELEGRAM_BOT_ROUTE_SECRET)% # Add to .env
Configure the Bundle:
Add to config/packages/boshurik_telegram_bot.yaml:
boshurik_telegram_bot:
api:
token: "%env(TELEGRAM_BOT_API_TOKEN)%"
proxy: "%env(TELEGRAM_BOT_PROXY_URL)%" # Optional
First Use Case:
Inject BotApi into a service/controller and send a message:
use TelegramBot\Api\BotApi;
public function __construct(private BotApi $api) {}
public function sendWelcomeMessage(int $chatId) {
$this->api->sendMessage([
'chat_id' => $chatId,
'text' => 'Welcome to our bot!'
]);
}
Handling Updates:
Use the UpdateHandler to process incoming Telegram updates:
use BoShurik\TelegramBotBundle\Handler\UpdateHandler;
public function __construct(private UpdateHandler $updateHandler) {}
public function handleUpdate(array $update) {
$this->updateHandler->handle($update);
}
Command Handling:
Register commands via the Command trait or by implementing CommandInterface:
use BoShurik\TelegramBotBundle\Command\CommandInterface;
class StartCommand implements CommandInterface {
public function getName(): string {
return 'start';
}
public function handle(BotApi $api, array $args, int $chatId) {
$api->sendMessage(['chat_id' => $chatId, 'text' => 'Hello!']);
}
}
Register in services.yaml:
services:
App\Command\StartCommand:
tags: [boshurik_telegram_bot.command]
Middleware Integration: Use middleware to pre/post-process updates or messages:
use BoShurik\TelegramBotBundle\Middleware\MiddlewareInterface;
class LoggingMiddleware implements MiddlewareInterface {
public function handle(array $update, callable $next) {
// Log update
return $next($update);
}
}
Register in services.yaml:
services:
App\Middleware\LoggingMiddleware:
tags: [boshurik_telegram_bot.middleware]
Webhook vs Polling:
TELEGRAM_BOT_ROUTE_SECRET.BotApi directly to fetch updates:
$updates = $this->api->getUpdates(['offset' => -1]);
Multi-Bot Management: Switch between bots dynamically:
$this->api->setBot('second'); // Uses the 'second' bot from config
Event Dispatching: Integrate with Symfony’s event system to trigger events on updates:
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
public function __construct(
private EventDispatcherInterface $dispatcher
) {}
public function handleUpdate(array $update) {
$this->dispatcher->dispatch(new TelegramUpdateEvent($update));
}
Database Persistence: Store chat data in Doctrine entities and fetch/save via repositories:
public function handleCommand(BotApi $api, int $chatId) {
$chat = $this->chatRepository->find($chatId);
if (!$chat) {
$chat = $this->chatRepository->save(new Chat($chatId));
}
$api->sendMessage(['chat_id' => $chatId, 'text' => 'Your ID: ' . $chat->getId()]);
}
Testing:
Mock BotApi for unit tests:
$mockApi = $this->createMock(BotApi::class);
$mockApi->method('sendMessage')->willReturn(['ok' => true]);
$this->container->set(BotApi::class, $mockApi);
Async Processing: Use Symfony Messenger to handle long-running tasks (e.g., sending media):
$this->messageBus->dispatch(new SendMediaMessage($chatId, $mediaPath));
Webhook URL Mismatch:
TELEGRAM_BOT_ROUTE_SECRET).curl:
curl -X POST "https://yourdomain.com/_telegram/your_secret" -d '{"update_id":123}'
Rate Limits:
429 Too Many Requests by implementing retries:
try {
$this->api->sendMessage($message);
} catch (Telegram\Exception\TelegramResponseException $e) {
if ($e->getCode() === 429) {
sleep($e->getRetryAfter());
$this->api->sendMessage($message);
}
}
Proxy Configuration:
socks5://), ensure it’s reachable and the format is correct. Test connectivity separately:
curl --proxy socks5://127.0.0.1:8888 https://api.telegram.org
Update Offset:
offset to avoid reprocessing updates:
$updates = $this->api->getUpdates(['offset' => $lastUpdateId + 1]);
Multiple Bots Conflict:
default_bot is set in config and avoid mixing bot tokens in the same request.Enable Verbose Logging:
Add to config/packages/monolog.yaml:
handlers:
telegram:
type: stream
path: "%kernel.logs_dir%/telegram_bot.log"
level: debug
channels: ["telegram"]
Then enable the channel in BoShurikTelegramBotBundle config:
boshurik_telegram_bot:
logging: true
Dump Updates: Log raw updates for debugging:
public function handleUpdate(array $update) {
file_put_contents(
'var/log/telegram_updates.log',
print_r($update, true) . PHP_EOL,
FILE_APPEND
);
}
Check Webhook Status: Verify webhook is set correctly via Telegram Bot API:
curl "https://api.telegram.org/bot<TOKEN>/getWebhookInfo"
Custom Update Handlers:
Extend UpdateHandler to add logic for specific update types:
class CustomUpdateHandler extends UpdateHandler {
protected function handleMessage(array $update) {
if ($update['message']['text'] === '/custom') {
$this->api->sendMessage([
'chat_id' => $update['message']['chat']['id'],
'text' => 'Custom response!'
]);
}
parent::handleMessage($update);
}
}
Register as a service and override the default handler in config.
Telegram API Extensions:
Extend BotApi to add custom methods:
use TelegramBot\Api\BotApi;
class ExtendedBotApi extends BotApi {
public function sendCustomMessage(array $params) {
return $this->sendMessage(array_merge($params, [
'reply_markup' => json_encode(['keyboard' => [['Custom']]])
]));
}
}
Bind the extended class in services.yaml:
services:
TelegramBot\Api\Bot
How can I help you explore Laravel packages today?