This guide is for developers who have already read the Basic Usage (BASIC.md) guide and want to unlock the full potential of the library.
Here, we will explore concepts like Middleware, custom Checkers, Plugins, and manual dependency injection.
- How to use
Middlewarefor cross-cutting concerns. - How to create custom
Checkersfor complex update routing. - How to organize your code with
Plugins. - How to manually build a
Telegraminstance and replace its components. - Advanced file handling techniques.
- Built-in Helpers:
Plugins,Middleware, andHandlers. - Stop request propagation
Middleware is a handler that wraps around your main RequestHandler.
This allows you to execute code before and after your primary logic, which is perfect for tasks such as:
- Logging incoming requests and outgoing responses.
- Checking user permissions before executing a command.
- Measuring the execution time of a handler.
- Adding global data to the
Requestobject.
A Middleware accepts a Request and the next RequestHandler in the chain. Your job is to eventually call $handler->handle($request) to pass control down the line.
Example: Logging Middleware
Let's create a Middleware that logs the ID of a received update before processing it and the response status code after.
<?php
namespace App\Middleware;
use AndrewGos\TelegramBot\Kernel\Middleware\MiddlewareInterface;
use AndrewGos\TelegramBot\Kernel\Request\Request;
use AndrewGos\TelegramBot\Kernel\RequestHandler\RequestHandlerInterface;
use AndrewGos\TelegramBot\Kernel\Response\Response;
use Psr\Log\LoggerInterface;
class LoggingMiddleware implements MiddlewareInterface
{
public function __construct(private LoggerInterface $logger) {}
public function process(Request $request, RequestHandlerInterface $handler): Response
{
$updateId = $request->getUpdate()->getUpdateId();
$this->logger->info("Processing update ID: {$updateId}");
// Pass control to the next handler in the chain
$response = $handler->handle($request);
$statusCode = $response->getStatusCode()->value;
$this->logger->info("Finished processing update ID: {$updateId} with status code: {$statusCode}");
return $response;
}
}How to use it?
Simply add an instance of your Middleware as the third argument to the HandlerGroup constructor.
<?php
use AndrewGos\TelegramBot\Kernel\HandlerGroup;
use AndrewGos\TelegramBot\Kernel\Checker\MessageCommandChecker;
// ...
// Assuming $startCommandHandler is defined as in BASIC.md
$logger = new MyPsr3Logger(); // Your PSR-3 compliant logger
$startGroup = new HandlerGroup(
new MessageCommandChecker('start'),
$startCommandHandler,
[
new App\Middleware\LoggingMiddleware($logger),
// You can add more middleware here
],
10, // Priority of the group
);
$telegram->getUpdateHandler()->addHandlerGroup($startGroup);The built-in Checkers (like MessageCommandChecker) might not be sufficient for complex logic.
You can easily create your own by implementing the CheckerInterface.
Example: A Checker that verifies if a message contains a specific word
<?php
namespace App\Checker;
use AndrewGos\TelegramBot\Entity\Update;
use AndrewGos\TelegramBot\Enum\UpdateTypeEnum;
use AndrewGos\TelegramBot\Kernel\Checker\CheckerInterface;
readonly class MessageTextContainsChecker implements CheckerInterface
{
public function __construct(
private string $needle,
) {}
public function check(Update $update): bool
{
if ($update->getType() !== UpdateTypeEnum::Message || $update->getMessage()->getText() === null) {
return false;
}
return str_contains($update->getMessage()->getText(), $this->needle);
}
}Usage in a HandlerGroup:
// ...
$supportGroup = new HandlerGroup(
new App\Checker\MessageTextContainsChecker('support'), // Will trigger on any message with the word "support"
$supportRequestHandler, // Your handler for support questions
);
$updateHandler->addHandlerGroup($supportGroup);As your bot grows, the number of HandlerGroups can become large.
Plugins allow you to group related handlers into a single logical module for better organization and reusability.
A plugin is a simple class that implements PluginInterface and returns an array (or any iterable) of HandlerGroups.
Example: A Plugin for Help Commands
<?php
namespace App\Plugin;
use AndrewGos\TelegramBot\Kernel\Checker\MessageCommandChecker;
use AndrewGos\TelegramBot\Kernel\HandlerGroup;
use AndrewGos\TelegramBot\Kernel\Plugin\PluginInterface;
use App\Handler\HelpCommandHandler; // Your /help command handler
use App\Handler\SupportCommandHandler; // Your /support command handler
class HelpPlugin implements PluginInterface
{
public function getHandlerGroups(): iterable
{
yield new HandlerGroup(
new MessageCommandChecker('help'),
new HelpCommandHandler(),
);
yield new HandlerGroup(
new MessageCommandChecker('support'),
new SupportCommandHandler(),
);
}
}Registering the Plugin:
<?php
// ...
$updateHandler = $telegram->getUpdateHandler();
$updateHandler->registerPlugin(new App\Plugin\HelpPlugin());While TelegramFactory is convenient, sometimes you need full control over the objects being created, for instance, to use your own HTTP client or to integrate with a framework's DI container.
You can assemble the Telegram instance manually.
<?php
use AndrewGos\ClassBuilder\ClassBuilder;
use AndrewGos\TelegramBot\Api\Api;
use AndrewGos\TelegramBot\Filesystem\Filesystem;
use AndrewGos\TelegramBot\Http\Client\HttpClient; // Can be replaced with your own PSR-18 client
use AndrewGos\TelegramBot\Http\Factory\TelegramRequestFactory;
use AndrewGos\TelegramBot\Kernel\UpdateHandler;
use AndrewGos\TelegramBot\Kernel\UpdateSource\GetUpdatesUpdateSource;
use AndrewGos\TelegramBot\Serializer\SerializerFactory;
use AndrewGos\TelegramBot\Telegram;
use AndrewGos\TelegramBot\ValueObject\BotToken;
use Monolog\Logger; // e.g., using Monolog
// 1. Token
$token = new BotToken('YOUR_BOT_TOKEN');
// 2. PSR-3 Logger
$logger = new Logger('my_bot_logger');
// ...configure your logger
// 3. Create the Api
$api = new Api(
$token,
new ClassBuilder(),
new TelegramRequestFactory(),
new HttpClient(), // You can substitute your PSR-18 client here
$logger,
new Filesystem(),
true, // throwOnErrorResponse
SerializerFactory::getDefaultApiSerializer(),
);
// 4. Create the UpdateHandler
$updateSource = new GetUpdatesUpdateSource($api); // Or PhpInputUpdateSource for webhooks
$updateHandler = new UpdateHandler(
$updateSource,
$api,
$logger,
);
// 5. Create the main Telegram object
$telegram = new Telegram(
$token,
$api,
$updateHandler,
);
// Now you can use $telegram as usual
$telegram->getUpdateHandler()->addHandlerGroup(/* ... */);
$telegram->getUpdateHandler()->listen();The library provides convenient methods for downloading files.
When using downloadFileToDirById or downloadFileById, you can get the detailed response from the getFile method to handle potential errors.
<?php
use AndrewGos\TelegramBot\Filesystem as Fs;
use AndrewGos\TelegramBot\Response\GetFileResponse;
// ...
$fileId = '...'; // File ID from a Message object
$targetDir = new Fs\Dir(new Fs\Path(__DIR__ . '/downloads'));
/** @var GetFileResponse $getFileResponse */
$getFileResponse = null;
$isSuccess = $telegram->getApi()->downloadFileToDirById(
$fileId,
$targetDir,
true, // overwrite
$getFileResponse, // Pass the variable by reference
);
if ($isSuccess) {
echo "File downloaded successfully!";
// $getFileResponse->getFile() contains the File object with file_path and file_size
} else {
echo "Failed to download file.";
if (!$getFileResponse->isOk()) {
// Log the error from the Telegram API
$logger->error("Telegram API error: " . $getFileResponse->getDescription());
}
}The library comes with a few pre-built, simple components to handle common tasks like logging, saving you from writing boilerplate code.
This plugin provides a simple way to log every single update your bot receives. It's incredibly useful for debugging during development.
- What it does: Registers a global
HandlerGroupthat matches any update and logs its JSON representation. - When to use it: When you want to see all incoming traffic to your bot for debugging purposes.
How to use it:
You need a PSR-3 compatible logger. Then, simply register the plugin.
<?php
use AndrewGos\TelegramBot\Kernel\Plugin\LogPlugin;
use Psr\Log\LoggerInterface; // Your PSR-3 logger
/**
* @var \AndrewGos\TelegramBot\Kernel\UpdateHandler $updateHandler
* @var LoggerInterface $logger
*/
$updateHandler->registerPlugin(new LogPlugin($logger));This middleware is more targeted than the plugin. It logs the incoming Update and the resulting Response for a specific HandlerGroup it's attached to.
- What it does: Logs the
Requestbefore it hits yourRequestHandlerand theResponseright after. - When to use it: When you need to debug a specific command or callback, to see both the input and the output of your handler.
How to use it:
Add it to the middleware array of a specific HandlerGroup.
<?php
use AndrewGos\TelegramBot\Kernel\HandlerGroup;
use AndrewGos\TelegramBot\Kernel\Middleware\LogMiddleware;
use AndrewGos\TelegramBot\Kernel\Checker\MessageCommandChecker;
//...
$startGroup = new HandlerGroup(
new MessageCommandChecker('start'),
$startCommandHandler,
[new LogMiddleware($logger)], // Add it here
);
$updateHandler->addHandlerGroup($startGroup);This is a simple handler whose only purpose is to log the update it receives.
- What it does: Serializes the
Updateobject to JSON and writes it to the log. - When to use it: It's perfect as a "catch-all" handler. By giving it a very low priority, you can log any updates that were not matched by any of your other
HandlerGroups. This helps you discover unexpected or unhandled events.
How to use it:
Combine it with an AnyChecker and set a low priority number (lower priority).
<?php
use AndrewGos\TelegramBot\Kernel\Checker\AnyChecker;
use AndrewGos\TelegramBot\Kernel\HandlerGroup;
use AndrewGos\TelegramBot\Kernel\RequestHandler\LogRequestHandler;
//...
$catchAllGroup = new HandlerGroup(
new AnyChecker(),
new LogRequestHandler($logger),
priority: -999, // Low number = low priority, so it runs last
);
$updateHandler->addHandlerGroup($catchAllGroup);If you want the request to be processed by only one handler, you can pass requestPropagationStop = true in the response.
Update handler will not use any request handlers after recieving response with requestPropagationStop = true.
This library provides default StopRequestPropagationMiddleware.php class,
that allows you to stop request propagation.
Set stopRequestPropagation in Response.php constructor
use AndrewGos\TelegramBot\Kernel\Response\Response;
use AndrewGos\TelegramBot\Enum\HttpStatusCodeEnum;
// In your request handler
return new Response(HttpStatusCodeEnum::NoContent, stopRequestPropagation: true);... or call stopRequestPropagation method of Response.php
use AndrewGos\TelegramBot\Kernel\Response\Response;
use AndrewGos\TelegramBot\Enum\HttpStatusCodeEnum;
// In your request handler, middleware, etc.
$response = new Response(HttpStatusCodeEnum::NoContent);
return $response->stopRequestPropagation();