Let’s enhance the bot with command handling using filters:
<?php declare(strict_types=1);use danog\MadelineProto\EventHandler\Attributes\Handler;use danog\MadelineProto\EventHandler\Filter\FilterCommand;use danog\MadelineProto\EventHandler\Message;use danog\MadelineProto\EventHandler\SimpleFilter\Incoming;use danog\MadelineProto\SimpleEventHandler;use danog\MadelineProto\ParseMode;if (file_exists('vendor/autoload.php')) { require_once 'vendor/autoload.php';} else { if (!file_exists('madeline.php')) { copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php'); } require_once 'madeline.php';}class CommandBot extends SimpleEventHandler{ public const ADMIN = "@me"; public function getReportPeers() { return [self::ADMIN]; } // Handle /start command #[FilterCommand('start')] public function startCommand(Message $message): void { $message->reply( message: "**Welcome to MadelineProto!**\n\nAvailable commands:\n/start - Show this message\n/ping - Check if bot is alive\n/echo <text> - Echo your message", parseMode: ParseMode::MARKDOWN ); } // Handle /ping command #[FilterCommand('ping')] public function pingCommand(Message $message): void { $message->reply("Pong! 🏓"); } // Handle /echo command with arguments #[FilterCommand('echo')] public function echoCommand(Message $message): void { $args = $message->commandArgs; $message->reply($args[0] ?? 'You did not provide any text!'); } // Handle all other incoming messages #[Handler] public function handleMessage(Incoming&Message $message): void { // Only respond to non-command messages if (!str_starts_with($message->message, '/')) { $message->reply("I received your message: " . $message->message); } }}CommandBot::startAndLoop('bot.madeline');
use danog\MadelineProto\EventHandler\Filter\FilterCommand;use danog\MadelineProto\EventHandler\Message;use danog\MadelineProto\EventHandler\SimpleFilter\HasMedia;use danog\MadelineProto\EventHandler\SimpleFilter\Incoming;// Send a photo#[FilterCommand('photo')]public function sendPhoto(Message $message): void{ $message->reply( message: "Here's a photo!", media: 'https://example.com/photo.jpg' );}// Handle incoming photos#[Handler]public function handlePhoto(Incoming&Message&HasMedia $message): void{ if ($message->media->photo ?? false) { $message->reply("Nice photo! I received it."); // Download the photo $message->media->downloadToDir('/path/to/save/'); }}// Get download link for any media#[FilterCommand('dl')]public function downloadLink(Message $message): void{ $reply = $message->getReply(Message::class); if (!$reply?->media) { $message->reply("Reply to a media message to get download link!"); return; } $reply->reply("Download: " . $reply->media->getDownloadLink());}
MadelineProto offers powerful filtering with PHP attributes and intersection types:
use danog\MadelineProto\EventHandler\Filter\FilterRegex;use danog\MadelineProto\EventHandler\Filter\FilterText;use danog\MadelineProto\EventHandler\Message\PrivateMessage;use danog\MadelineProto\EventHandler\SimpleFilter\FromAdmin;use danog\MadelineProto\EventHandler\SimpleFilter\IsReply;// Match exact text#[FilterText('hello')]public function greet(Message $message): void{ $message->reply("Hello there!");}// Match with regex#[FilterRegex('/.*(mt?proto)[^.]?.*/i')]public function mentionMTProto(Message $message): void{ $message->reply("Did you mean MadelineProto instead of " . $message->matches[1] . "?");}// Only from admins, in private chats, that are replies#[Handler]public function adminReply(PrivateMessage&FromAdmin&IsReply $message): void{ $original = $message->getReply(Message::class); $message->reply("Admin replied to: " . $original->message);}
#[Handler]public function handleMessage(Message $message): void{ $userId = $message->senderId; $chatId = $message->chatId; // Get full user info $userInfo = $this->getInfo($userId); // Get current bot info $me = $this->getSelf(); $this->logger("User: " . $userInfo['User']['first_name']);}