tourze/telegram-bot-bundle
tourze/telegram-bot-bundle is a Symfony bundle that streamlines Telegram bot integration in PHP applications. It provides framework wiring for bot services and configuration, making it easier to register bots, process updates, and build messaging or command workflows with minimal setup.
tourze/telegram-bot-bundle is distributed as a Symfony bundle (not a native Laravel package). That single fact shapes everything below: you can use it in a Laravel app, but you will be hand-wiring what Symfony Flex would normally do for you.
Minimal steps:
0.1.2 → 0.2.0), so minor bumps can carry breaking changes. Use composer require tourze/telegram-bot-bundle:0.2.0 rather than ^0.2 until you've read the diff.0.1.2...0.2.0) — no changelog entries, no migration notes. Before upgrading, open that compare view and scan for changed constructor signatures, renamed service IDs, and changed config keys. Treat this as mandatory, not optional.vendor/tourze/telegram-bot-bundle/:
composer.json — what it depends on (likely a sibling tourze/telegram-bot-api or an HTTP client wrapper). Your real API surface often lives in the dependency, not the bundle.src/DependencyInjection/*Extension.php — the authoritative list of config keys and service definitions.src/Resources/config/*.yaml — service IDs you'll need to reference manually under Laravel.README.md — tourze packages frequently have thin or Chinese-language docs; the code is the documentation.$this->app->singleton(...) per service ID) or, more practically, instantiate the underlying client yourself and use the bundle only as a config-source reference.getMe / getWebhookInfo. Getting one message out end-to-end validates token config, HTTP client wiring, and error handling in one pass.If you are on a pure Symfony app, steps 4 collapses to enabling the bundle in config/bundles.php and importing its config — the package is on home turf there.
Configuration as the seam. Put the bot token and any per-bot options in config/services.php (Laravel) or a dedicated config file, and resolve them via env(). Never let the token leak into a service that gets serialized into a queued job payload — pass a bot name, resolve the client inside the job.
Wrap the client, don't inject it everywhere. The bundle's client is a vendor type. Put a thin TelegramNotifier interface in front of it so that a breaking change in 0.3.0 touches one file instead of forty, and so you can fake it in tests.
Queue outbound sends. Telegram enforces roughly 30 messages/second per bot and will return 429 with a retry_after field. Wrap sends in a job with retryUntil/backoff, and use RateLimited middleware keyed per chat to avoid hammering a single conversation — Telegram applies stricter per-chat limits than the global one.
Webhook controller as an invokable. Register a single route (POST /telegram/webhook) excluded from CSRF, validate the X-Telegram-Bot-Api-Secret-Token header against config, then dispatch to a handler. Keep the controller returning 200 fast — Telegram retries on non-2xx and on slow responses, which duplicates updates.
Route updates, don't switch on them. Map message, callback_query, edited_message to handler classes via a small registry rather than a growing match block. This mirrors how the bundle's own event/dispatcher wiring (if present in 0.2.0) is structured and keeps new update types additive.
Multi-bot. If you run more than one bot, use named connections in config and resolve per-name. Avoid static/singleton state in the client — that pattern breaks the moment a second token exists.
autowired services, tagged iterators, and an EventDispatcherInterface. Laravel's container is not a drop-in. Symptoms: "Target [SomeInterface] is not instantiable" at resolve time. Fix by explicitly binding the interfaces the bundle's services consume.DependencyInjection/ and any public interfaces; those are where 0.x breaks live. Consider depending on the underlying telegram-bot-api package directly and skipping the bundle entirely if you're on Laravel — the bundle's value is DI glue you're rebuilding anyway.getUpdates polling, setWebhook will fail with 409 Conflict: can't use getUpdates while webhook is active. Call deleteWebhook before switching, and script this in your deploy rather than doing it by hand.setWebhook must be re-run whenever the URL or certificate changes, and silently keeps the old URL otherwise. Make it an idempotent artisan command that runs on deploy.sendDocument.php artisan config:clear (or cache:clear). A stale cached config pointing at a test token is a classic half-hour of confusion.{"ok":false,"error_code":...,"description":...} — the description is usually precise ("chat not found", "message is too long", "Bad Request: can't parse entities"). Wrap the client call and log both request method and full response on non-2xx.parse_mode message must be escaped, or the whole send fails with can't parse entities. Escape at the edge, or omit parse_mode for untrusted content.How can I help you explore Laravel packages today?