Skip to main content
Version: 4.x

Handlers

Concept

The framework provides to you a nice API event-like to handling incoming updates:

use SergiX44\Nutgram\Nutgram;

$bot = new Nutgram($_ENV['TOKEN']);

$bot->onMessage(function (Nutgram $bot) {
$bot->sendMessage('You sent a message!');
});

$bot->run();

Every ->on* handler is called based on the update type defined in Telegram's update object, there are also some specific handlers, which may respond based on specific patterns or types of messages.

As you can also see from the example above, some required parameters (like the chat_id) can be omitted, while the bot is in the context of managing an update, so those fields are automatically extracted from the current update.

Of course, you can override them at any time, simply by specifying them in the method call.

Available Handlers

Here a full list of all the handler that listens to specific type of updates:

Update Handlers

 onUpdate($callable)
Handles any incoming update.
 onMessage($callable)
Handles any incoming message.
 onMessageType(string $type, $callable)
Handles messages defined by type.
 onEditedMessage($callable)
Handles any incoming edited message.
 onChannelPost($callable)
Handles any message posted in a channel where the bot is administrator.
 onEditedChannelPost($callable)
Handles any message edited in a channel where the bot is administrator.
 onInlineQuery($callable)
Handles any incoming inline query.
 onInlineQueryText(string $pattern, $callable)
Handles any incoming inline query with a specific pattern, similar to `onText`.
 onChosenInlineResult($callable)
Handles any incoming chosen inline result.
 onChosenInlineResultQuery($callable)
Handles any incoming chosen inline result with a specific pattern, similar to `onText`.
 onCallbackQuery($callable)
Handles any incoming callback query.
 onCallbackQueryData(string $pattern, $callable)
Handles callback query with a specific pattern, similar to `onText`.
 onShippingQuery($callable)
Handles any incoming shipping query.
 onPreCheckoutQuery($callable)
Handles any incoming pre checkout query.
 onPreCheckoutQueryPayload(string $pattern, $callable)
Handles any incoming pre checkout query with a specific payload pattern.
 onUpdatePoll($callable)
Handles any incoming poll.
 onPollAnswer($callable)
Handles any incoming poll answer.
 onMyChatMember($callable)
Handles any chat member when updated.
 onChatMember($callable)
Handles any chat member in other chats when updated.
 onChatJoinRequest($callable)
Handles any chat join request.

Message Handlers

 onText(string $pattern, $callable, UpdateType $target = UpdateType::MESSAGE)
Handles text messages that match the given pattern (regex or parameters).
 onCommand(string $command, $callable, UpdateType $target = UpdateType::MESSAGE)
Handles text messages that begin with `/`.
Automatically parses commands like `cmd@botname`.
 onAnimation($callable, UpdateType $target = UpdateType::MESSAGE)
Handles animation messages
 onAudio($callable, UpdateType $target = UpdateType::MESSAGE)
Handles audio messages.
 onDocument($callable, UpdateType $target = UpdateType::MESSAGE)
Handles document messages.
 onPhoto($callable, UpdateType $target = UpdateType::MESSAGE)
Handles photo messages.
 onSticker($callable, UpdateType $target = UpdateType::MESSAGE)
Handles sticker messages.
 onVideo($callable, UpdateType $target = UpdateType::MESSAGE)
Handles video messages.
 onVideoNote($callable, UpdateType $target = UpdateType::MESSAGE)
Handles video_note messages.
 onVoice($callable, UpdateType $target = UpdateType::MESSAGE)
Handles voice messages.
 onContact($callable, UpdateType $target = UpdateType::MESSAGE)
Handles contact messages.
 onDice($callable, UpdateType $target = UpdateType::MESSAGE)
Handles dice messages.
 onGame($callable)
Handles game messages.
 onMessagePoll($callable, UpdateType $target = UpdateType::MESSAGE)
Handles poll messages.
 onVenue($callable, UpdateType $target = UpdateType::MESSAGE)
Handles venue messages.
 onLocation($callable, UpdateType $target = UpdateType::MESSAGE)
Handles location messages.
 onStory($callable, UpdateType $target = UpdateType::MESSAGE)
Handles story messages.
 onNewChatMembers($callable, UpdateType $target = UpdateType::MESSAGE)
Handles new_chat_members messages.
 onLeftChatMember($callable, UpdateType $target = UpdateType::MESSAGE)
Handles left_chat_member messages.
 onNewChatTitle($callable, UpdateType $target = UpdateType::MESSAGE)
Handles new_chat_title messages.
 onNewChatPhoto($callable, UpdateType $target = UpdateType::MESSAGE)
Handles new_chat_photo messages.
 onDeleteChatPhoto($callable, UpdateType $target = UpdateType::MESSAGE)
Handles delete_chat_photo messages.
 onGroupChatCreated($callable)
Handles group_chat_created messages.
 onSupergroupChatCreated($callable)
Handles supergroup_chat_created messages.
 onChannelChatCreated($callable, UpdateType $target = UpdateType::MESSAGE)
Handles channel_chat_created messages.
 onMessageAutoDeleteTimerChanged($callable, UpdateType $target = UpdateType::MESSAGE)
Handles message_auto_delete_timer_changed messages.
 onMigrateToChatId($callable)
Handles migrate_to_chat_id messages.
 onMigrateFromChatId($callable)
Handles migrate_from_chat_id messages.
 onPinnedMessage($callable, UpdateType $target = UpdateType::MESSAGE)
Handles pinned_message messages.
 onInvoice($callable)
Handles invoice messages.
 onSuccessfulPayment($callable)
Handles successful_payment messages.
 onSuccessfulPaymentPayload(string $pattern, $callable)
Handles successful_payment messages with a specific payload pattern.
 onConnectedWebsite($callable)
Handles connected_website messages.
 onPassportData($callable)
Handles any incoming passport data messages.
 onProximityAlertTriggered($callable)
Handles proximity_alert_triggered messages.
 onForumTopicCreated($callable)
Handles any forum topic created.
 onForumTopicClosed($callable)
Handles any forum topic closed.
 onForumTopicReopened($callable)
Handles any forum topic reopened.
 onVideoChatScheduled($callable, UpdateType $target = UpdateType::MESSAGE)
Handles video_chat_scheduled messages.
 onVideoChatStarted($callable, UpdateType $target = UpdateType::MESSAGE)
Handles video_chat_started messages.
 onVideoChatEnded($callable, UpdateType $target = UpdateType::MESSAGE)
Handles video_chat_ended messages.
 onVideoChatParticipantsInvited($callable, UpdateType $target = UpdateType::MESSAGE)
Handles video_chat_participants_invited messages.
 onWebAppData($callable)
Handles web_app_data messages.

Special Handlers

 fallback($callable)
This handler if defined will be called if no handler, specific or generic, has been found for the current update.
 fallbackOn(string $type, $callable)
This handler has the same behavior as the previous one, but allows you to put a filter on the type of updates it can handle.
 onException($callable)
This handler will be called whenever the handling of an update throws an exception, if undefined the exception will not be caught.
Check the next paragraph for more details.
 onApiError($callable)
This handler will be called every time a call to Telegram's api fails, if undefined the exception will not be caught.
Check the next paragraph for more details.
 beforeApiRequest($callable)
This handler will be called before every call to Telegram's api, if undefined the call will be made without any modification.
Check the next paragraph for more details.
 afterApiRequest($callable)
This handler will be called after every call to Telegram's api, if undefined the call will be made without any modification.
Check the next paragraph for more details.

Specific & Special Handlers

onCommand

For the implicit style see the registerCommand section.

use SergiX44\Nutgram\Nutgram;

$bot = new Nutgram($_ENV['TOKEN']);

// Called when a message contains the command "/start someParameter"
$bot->onCommand('start {parameter}', function (Nutgram $bot, $parameter) {
$bot->sendMessage("The parameter is {$parameter}");
});

// Called on command "/help"
$bot->onCommand('help', function (Nutgram $bot) {
$bot->sendMessage('Help me!');
});

$bot->run();

registerCommand

A different and clean way to register commands implicitly.

// 1. create a command class like "StartCommand.php":

namespace App\Telegram\Commands;

use SergiX44\Nutgram\Handlers\Type\Command;
use SergiX44\Nutgram\Nutgram;

class StartCommand extends Command
{
protected string $command = 'start';

protected ?string $description = 'A lovely start command';

public function handle(Nutgram $bot): void
{
$bot->sendMessage('Hello there!');
}
}

// 2. Register StartCommand inside Nutgram

$bot->registerCommand(StartCommand::class);

onText

For text messages, is possible also put parameters to match a regex, or to match part of text:

use SergiX44\Nutgram\Nutgram;

$bot = new Nutgram($_ENV['TOKEN']);

// ex. called when a message contains "My name is Mario"
$bot->onText('My name is {name}', function (Nutgram $bot, $name) {
$bot->sendMessage("Hi {$name}");
});

// ex. called when a message contains "I want 6 pizzas"
$bot->onText('I want ([0-9]+) pizzas', function (Nutgram $bot, $n) {
$bot->sendMessage("You will get {$n} pizzas!");
});

$bot->run();

onMessageType

It's like the onMessage handler, but you can specify to which type of message you should handle:

use SergiX44\Nutgram\Nutgram;
use SergiX44\Nutgram\Telegram\Properties\MessageType;

$bot = new Nutgram($_ENV['TOKEN']);

// Called only when you send a photo
$bot->onMessageType(MessageType::PHOTO, function (Nutgram $bot) {
$photos = $bot->message()->photo;
$bot->sendMessage('Nice pic!');
});

// Called only when you send an audio file
$bot->onMessageType(MessageType::AUDIO, function (Nutgram $bot) {
$audio = $bot->message()->audio;
$bot->sendMessage('I love this song!');
});

$bot->run();

You can see all the constants, in the MessageType::class.

onCallbackQueryData

It's like the onText handler, but you can specify to which data contained in CallbackQuery to handle:

use SergiX44\Nutgram\Nutgram;

$bot = new Nutgram($_ENV['TOKEN']);

$bot->onCommand('start', function (Nutgram $bot) {
$bot->sendMessage(
text: 'Choose an option:',
reply_markup: InlineKeyboardMarkup::make()->addRow(
InlineKeyboardButton::make('One', callback_data: 'one'),
InlineKeyboardButton::make('Two', callback_data: 'two'),
InlineKeyboardButton::make('Cancel', callback_data: 'cancel'),
)
);
});

$bot->onCallbackQueryData('one|two', function (Nutgram $bot) {
$bot->sendMessage('Nice!');
$bot->answerCallbackQuery();
});

$bot->onCallbackQueryData('cancel', function (Nutgram $bot) {
$bot->sendMessage('Canceled!');
$bot->answerCallbackQuery();
});

$bot->run();

The same thing also applies for custom parameters:

use SergiX44\Nutgram\Nutgram;

$bot = new Nutgram($_ENV['TOKEN']);

$bot->onCommand('start', function (Nutgram $bot) {
$bot->sendMessage(
text: 'Choose an option:',
reply_markup: InlineKeyboardMarkup::make()->addRow(
InlineKeyboardButton::make('One', callback_data: 'number 1'),
InlineKeyboardButton::make('Two', callback_data: 'number 2'),
InlineKeyboardButton::make('Cancel', callback_data: 'cancel'),
)
);
});

$bot->onCallbackQueryData('number {param}', function (Nutgram $bot, $param) {
$bot->sendMessage($param); // 1 or 2
$bot->answerCallbackQuery();
});

$bot->onCallbackQueryData('cancel', function (Nutgram $bot) {
$bot->sendMessage('Canceled!');
$bot->answerCallbackQuery();
});

$bot->run();

fallback

This handler, if defined, will be called every time an Update will not match any other defined handler:

use SergiX44\Nutgram\Nutgram;

$bot = new Nutgram($_ENV['TOKEN']);

// But the user send something else than /start
$bot->onCommand('start', function (Nutgram $bot) {
$bot->sendMessage('Started!');
});

$bot->fallback(function (Nutgram $bot) {
$bot->sendMessage('Sorry, I don\'t understand.');
});

$bot->run();

fallbackOn

This has the same behaviour of the fallback, but allow you to define handlers based on the Update type:

use SergiX44\Nutgram\Nutgram;
use SergiX44\Nutgram\Telegram\Properties\UpdateType;

$bot = new Nutgram($_ENV['TOKEN']);

// define some handlers ...

// Called only for unmatched callback queries
$bot->fallbackOn(UpdateType::CALLBACK_QUERY, function (Nutgram $bot) {
$bot->answerCallbackQuery();
$bot->editMessageReplyMarkup([/* ... */]);
});

// Called only for unmatched messages
$bot->fallbackOn(UpdateType::MESSAGE, function (Nutgram $bot) {
$bot->sendMessage('Sorry, I don\'t understand.');
});

$bot->run();

You can see all the constants, in the UpdateType::class.

onException

This handler, if defined, will be called if something on your other handlers goes wrong, passing the $exception as second argument:

use SergiX44\Nutgram\Nutgram;

$bot = new Nutgram($_ENV['TOKEN']);

// define some handlers ...

// and exception is thrown...
$bot->onMessage(function (Nutgram $bot) {
// do stuff
throw new Exception('Oh no!');
});

// ... and passed to the exception handler
$bot->onException(function (Nutgram $bot, \Throwable $exception) {
echo $exception->getMessage(); // Oh no!
$bot->sendMessage('Whoops!');
});

$bot->run();
tip

For a more specific exception handling, you can visit the Handling Exceptions section.

onApiError

The same concept of the onException, but for outgoing requests:

use SergiX44\Nutgram\Nutgram;
use SergiX44\Nutgram\Telegram\Exceptions\TelegramException;

$bot = new Nutgram($_ENV['TOKEN']);

$bot->onMessage(function (Nutgram $bot) {
$bot->sendMessage(
text: 'Invalid call!',
chat_id: null,
);
});

$bot->onApiError(function (Nutgram $bot, TelegramException $exception) {
echo $exception->getMessage(); // Bad Request: chat not found
echo $exception->getCode(); // 400
});

$bot->run();
tip

For a more specific error handling, you can visit the Handling Exceptions section.

beforeApiRequest

This handler, if defined, will be called before every outgoing request, passing the $request as second argument:

use SergiX44\Nutgram\Nutgram;

$bot = new Nutgram($_ENV['TOKEN']);

$bot->beforeApiRequest(function (Nutgram $bot, array $request, string $endpoint) {
// modify the outgoing request changing the text of the message if the endpoint is sendMessage
if($endpoint === 'sendMessage'){
$request['json']['text'] = 'Modified!';
}

return $request;
});

$bot->run();

afterApiRequest

This handler, if defined, will be called after every outgoing request, passing the $response as second argument:

use SergiX44\Nutgram\Nutgram;

$bot = new Nutgram($_ENV['TOKEN']);

$bot->afterApiRequest(function (Nutgram $bot, object $response) {
// print a value from the response
echo $response->result->text;

// modify the response
$response->result->text = 'Modified!';

return $response;
});

$bot->run();

Handlers Pattern

Nutgram offers a powerful way to handle commands and specific handlers using a pattern system based on regex.
You can use regex to match specific parts of the text, and you can also use named parameters to extract values from the text.

// called on command "/start"
$bot->onCommand('start', function (Nutgram $bot) {
$bot->sendMessage('This is the start command!');
});

// called on command "/hello Mario" (named parameter)
$bot->onCommand('hello {name}', function (Nutgram $bot, string $name) {
$bot->sendMessage("Hi, {$name}!");
});

// called on text "I want 6 portions of cake" (regex)
$bot->onText('I want ([0-9]+) portions of (pizza|cake)', function (Nutgram $bot, string $amount, string $dish) {
$bot->sendMessage("You will get {$amount} portions of {$dish}!");
});

Case insensitive

By default, the pattern is case sensitive, but you can make it case insensitive by calling the insensitive() method on the handler:

// called only on text "hello"
$bot->onText('hello', function (Nutgram $bot) {)
$bot->sendMessage('Hello!');
});

// called on text "Hello", "HELLO", "hElLo" and so on
$bot->onText('hello', function (Nutgram $bot) {)
$bot->sendMessage('Hello!');
})->insensitive();

You can also use the insensitive() method in group method:

$bot->group(function () use (Nutgram $bot) {
$bot->onText('hello', function (Nutgram $bot) {)
$bot->sendMessage('Hello!');
});
$bot->onText('hi', function (Nutgram $bot) {)
$bot->sendMessage('Hi!');
});
})->insensitive();

Named parameters constraints

You may constrain the format of your named parameters using the where method on a handler. The where method accepts the name of the parameter and a regular expression defining how the parameter should be constrained:

$bot->onCommand('hello {name}', HelloCommand::class)
->where('name', '[A-Za-z]+');

$bot->onCommand('hello {name} {age}', HelloCommand::class)
->where(['name' => '[A-Za-z]+', 'age' => '[0-9]+']);
info

By default, parameters are constrained by the default regular expression .*.

Here is the list of the other available constraints:

  • whereIn(string $parameter, array $values)
    The parameter must be contained in the given array.
$bot->onCommand('confirm {answer}', ConfirmCommand::class)
->whereIn('answer', ['y','n']);
  • whereAlpha(string $parameter)
    The parameter must be entirely alphabetic characters.
$bot->onCommand('hello {name}', HelloCommand::class)
->whereAlpha('name');
  • whereNumber(string $parameter)
    The parameter must be entirely numeric characters.
$bot->onCommand('age {age}', AgeCommand::class)
->whereNumber('age');
  • whereAlphaNumeric(string $parameter)
    The parameter must be entirely alpha-numeric characters.
$bot->onCommand('hello {name}', HelloCommand::class)
->whereAlphaNumeric('name');

You can also use the where methods in group method:

$bot->group(function () use (Nutgram $bot) {
$bot->onCommand('create {name}', CreateCommand::class);
$bot->onCommand('delete {name}', DeleteCommand::class);
})->whereAlpha('name');

Custom parameters binding

You can also bind custom parameters to the handler using the bindParameter method:

$bot = new Nutgram($_ENV['TOKEN']);
$bot->bindParameter('hex', function(Container $container, string $value){
return Color::fromHex($value);
});

$bot->onCommand('color {hex}', function(Nutgram $bot, Color $color){
$bot->sendMessage("The color is {$color->name}");
});

Handlers Priority

caution

If you declare handlers, they will block the execution of handlers.
Please keep this in mind when using Nutgram.

Some examples to clarify this:

// Input text: something

// Specific handler: ✅ it will be executed!
$bot->onText('something', SomethingHandler::class);

// Generic handler: ❌ it will not be executed!
$bot->onMessageType(MessageType::TEXT, MessageTypeTextHandler::class);

// Generic handler: ❌ it will not be executed!
$bot->onMessage(MessageHandler::class);

Disable handler registration

You can disable the registration of a specific handler, using the unless method:

$donationEnabled = false;

$bot->onCommand('donate', DonateConversation::class)->unless($donationEnabled);
$bot->onCommand('start donate', DonateConversation::class)->unless($donationEnabled);
$bot->onPreCheckoutQuery(PreCheckoutQueryHandler::class)->unless($donationEnabled);
$bot->onSuccessfulPayment(SuccessfulPaymentHandler::class)->unless($donationEnabled);

// or

$bot->group(function(){
$bot->onCommand('donate', DonateConversation::class);
$bot->onCommand('start donate', DonateConversation::class);
$bot->onPreCheckoutQuery(PreCheckoutQueryHandler::class);
$bot->onSuccessfulPayment(SuccessfulPaymentHandler::class);
})->unless($donationEnabled);
caution

The unless method will be executed only when the handler is registered, not when it is executed.
If you need to stop the execution of a handler at runtime, you can use a Middleware.

Automatically register bot commands

The framework can also automatically set the bot commands for you, if you configure the description on it:

use SergiX44\Nutgram\Nutgram;

$bot = new Nutgram($_ENV['TOKEN']);

// Called on command "/start"
// It's possible to set a description for each command
// this WILL be automatically registered
$bot->onCommand('start', function (Nutgram $bot) {
return $bot->sendMessage('Hello, world!');
})->description('The start command!');

// Called on command "/secret"
// this WILL NOT be automatically registered
$bot->onCommand('secret', function (Nutgram $bot) {
return $bot->sendMessage('Shhh');
});

Language code support

Nutgram also supports the ability to set the language code for each command.

To set a command for a specific language, you can use the description method with an array of two-letter ISO 639-1 language code as keys and the description as value.

You can specify * as a wildcard for all languages not explicitly set.

No language code

Commands will be applied to all users from the given scope, for whose language there are no dedicated commands.

$bot->onCommand('start', StartCommand::class)->description('The start command!');
//or
$bot->onCommand('start', StartCommand::class)->description(['*' => 'The start command!']);

Specific language code

$bot->onCommand('start', StartCommand::class)->description([
'it' => 'Il comando start!', // Italian
'es' => 'El comando start!', // Spanish
'*' => 'The start command!', // All other languages
]);

Scope support

Command Scopes allows for more granular control over which users or groups can see specific commands in the bot.

How to set a scope

Just use the scope method:

//single scope
$bot
->onCommand('start', StartCommand::class)
->description('Start command')
->scope(new BotCommandScopeAllPrivateChats);

// multiple scope (multiple calls)
$bot
->onCommand('start', StartCommand::class)
->description('Start command')
->scope(new BotCommandScopeAllPrivateChats)
->scope(new BotCommandScopeAllGroupChats);

// multiple scope (as array)
$bot
->onCommand('start', StartCommand::class)
->description('Start command')
->scope([
new BotCommandScopeAllPrivateChats,
new BotCommandScopeAllGroupChats,
]);

Available scopes

  • new BotCommandScopeDefault();
  • new BotCommandScopeAllChatAdministrators();
  • new BotCommandScopeAllGroupChats();
  • new BotCommandScopeAllPrivateChats();
  • new BotCommandScopeChat(chat_id: 123);
  • new BotCommandScopeChatAdministrators(chat_id: 123);
  • new BotCommandScopeChatMember(chat_id: 123, user_id: 987);

For a description of each scope, please refer to the official documentation page.

Registering commands

To register the commands, you can use the registerMyCommands method, which will automatically call the setMyCommands method:

$bot->registerMyCommands();

And the result will be:

commands

caution

Please do not use the registerMyCommands method in the same file where you register your bot handlers when using the Webhook running mode, because the bot will register your commands on every webhook call, causing a lot of useless requests. Just call the method manually or after a deploy.

OOP

So far you have seen handlers defined only as closures. But the framework, any definition that accepts a $callable, also accepts a class-method definition, or invokable classes, like this:

use SergiX44\Nutgram\Nutgram;

class MyCommand {

public function __invoke(Nutgram $bot, $param)
{
//do stuff
}
}
use SergiX44\Nutgram\Nutgram;

$bot = new Nutgram($_ENV['TOKEN']);

// all of those are valid definitions:
$bot->onCommand('start {param}', MyCommand::class); // with __invoke
$bot->onCommand('start1 {param}', [MyCommand::class, 'handle']); // class-method
$bot->onCommand('start2 {param}', [$instance, 'handle']); // instance-method

$bot->run();