Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Tdlib Bundle Laravel Package

yaroslavche/tdlib-bundle

Symfony bundle for integrating TDLib into PHP applications, with service configuration and a convenient wrapper for building Telegram clients. It helps wire TDLib dependencies and use Telegram’s API from Symfony services.

View on GitHub
Deep Wiki
Context7

Getting Started

The bundle is a thin Symfony integration over the yaroslavche/tdlib-php PHP extension, which itself wraps Telegram's TDLib. That means the hardest dependency is not the bundle — it is the native TDLib library and the PHP extension compiled against your PHP version.

  • Install the PHP extension first: build TDLib, then yaroslavche/tdlib-php. Confirm with php -m | grep -i tdlib and php -r "var_dump(extension_loaded('tdlib'));". If class_exists(...)/function_exists('tdCreate') is false, the bundle will fail at container build, not at runtime.
  • composer require yaroslavche/tdlib-bundle, then confirm the bundle is registered in config/bundles.php (Flex usually handles it; without Flex add it manually).
  • Create config/packages/tdlib.yaml. At minimum you need api_id and api_hash from https://my.telegram.org → API development tools (these are per-application, not per-account), plus a writable database directory. Feed them via env vars: %env(TDLIB_API_ID)%, %env(TDLIB_API_HASH)%.
  • Look first at three files in the repo: DependencyInjection/Configuration.php (the real config tree — the README is likely partial), Resources/config/* (actual service IDs and whether a default client is autowired or you must build one from a factory), and the README's usage example.
  • First use case: a one-off console command that creates the client, sends TdlibParameters and GetAuthorizationState, then walks the auth flow interactively (phone number → code → optional 2FA password). Run it once, complete auth, and TDLib persists the session to the database directory. Every subsequent run reuses it.

Implementation Patterns

  • Auth is a one-shot, stateful command. Treat "login" as an interactive CLI command, not a web endpoint. After the session exists on disk, normal code just loads the client. Keep the auth command in your app so you can re-run it when a session is revoked.

  • Long-running worker as the update loop. TDLib delivers updates via a blocking receive call. Structure it as:

    while (true) {
        $update = $client->receive(1.0);        // block up to 1s
        if ($update === null) { continue; }
        $dispatcher->dispatch($update, TdlibUpdateEvent::class);
    }
    

    Run it under Supervisor/systemd. Never call receive() inside an HTTP request — it will hang the worker until timeout.

  • Route update types through Symfony's EventDispatcher. Map updateNewMessage, updateMessageSendSucceeded, updateMessageContent, updateConnectionState, etc. onto your own event/listener classes. This is the natural extension point and keeps application code free of TDLib type-switching.

  • Keep outbound sends on a queue. send() is asynchronous — it returns immediately and results arrive as update objects. Pair tdSend with Messenger: a handler consumes SendMessage messages and issues the TDLib call; a separate listener reconciles the updateMessageSendSucceeded/updateMessageSendFailed. This gives you retries and backpressure for free.

  • Wrap the client in your own service. The bundle likely exposes a default client service (check Resources/config for the exact ID). Inject your own TelegramClient wrapper around it so controllers, commands, and listeners do not touch the raw extension API — this is what makes mocking and a future swap to Bot API feasible.

  • Multiple accounts/bots = multiple clients. Each TDLib client needs its own database directory. Define one service per account (or a client factory keyed by account ID) and keep them in separate workers; do not multiplex two accounts on one client handle.

  • Thin controllers, fat commands. Controllers should validate input + dispatch a SendMessage message; a CLI worker does the TDLib work. This is the only pattern that scales when TDLib is blocking and rate-limited.

Gotchas and Tips

  • The extension is the failure point, not the bundle. TDLib compilation is slow (C++) and the PHP extension must be rebuilt for each PHP minor version. Budget a day for the first environment; document the build in your Docker image so CI and prod match.
  • receive() blocks and is not interruptible in a friendly way. Use a short timeout so your loop can check a shutdown flag, or signal the process and let Supervisor restart. Don't wrap it in PHP set_time_limit logic — this is a daemon.
  • Deleting the database directory logs the account out. Re-auth too often and you hit Telegram flood limits. Back the directory up; never point two clients at it concurrently (corruption, not just errors).
  • Everything is asynchronous. send() returns nothing useful; the response to a request arrives as an update keyed by @extra. If you need request/response semantics, stash the @extra in a pending-request map and resolve it in the update listener. This is the single most common source of "why is my message missing" bugs.
  • Flood/rate limits are real. Handle error 429 / FLOOD_WAIT_* in your listener with exponential backoff. Do not let a Messenger retry policy hammer TDLib.
  • Log verbosity is a footgun. TDLib is extremely chatty at high verbosity (it logs every update body). Turn it down in prod, keep it high for the first auth run. Route it to a separate file, not the app log.
  • Config quirks. The bundle is small (11 stars, no dependents) and its README may not match the actual config tree — read Configuration.php. Service autowiring may or may not work out of the box; be prepared to alias or explicitly define the client service.
  • Pin versions. With a tiny ecosystem, minor bumps can break the extension/bundle contract. Commit composer.lock and pin the extension in your Dockerfile.
  • Make it testable. Guard CI against the extension being absent (extension_loaded('tdlib') in phpunit.xml skip groups), and program against an interface so unit tests never touch TDLib. Integration tests that actually talk to Telegram should be opt-in and run against a throwaway account.
  • Debugging tip: when an update looks empty, dump the raw array before your event dispatch — TDLib's object graph is deep and lossy if you type-cast early.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle