Skip to main content
Version: 2.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 $opt array.

Available Handlers

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

Handler MethodTypeDescription
onCommand(string $command, $callable)SpecificHandles text messages that begin with /.
Automatically parses commands like cmd@botname.
onText(string $pattern, $callable)SpecificHandles text messages that match the given pattern (regex or parameters).
onMessageType(string $type, $callable)SpecificHandles messages defined by type.
onCallbackQueryData(string $pattern, $callable)SpecificHandles callback query with a specific pattern, similar to onText.
onMessage($callable)GenericHandles any incoming message.
onCallbackQuery($callable)GenericHandles any incoming callback query.
onEditedMessage($callable)GenericHandles any incoming edited message.
onChannelPost($callable)GenericHandles any message posted in a channel where the bot is administrator.
onEditedChannelPost($callable)GenericHandles any message edited in a channel where the bot is administrator.
onInlineQuery($callable)GenericHandles any incoming inline query.
onChosenInlineResult($callable)GenericHandles any incoming chosen inline result.
onShippingQuery($callable)GenericHandles any incoming shipping query.
onPreCheckoutQuery($callable)GenericHandles any incoming pre checkout query.
onPoll($callable)GenericHandles any incoming poll.
onPollAnswer($callable)GenericHandles any incoming poll answer.
onMyChatMember($callable)GenericHandles any chat member when updated.
onChatMember($callable)GenericHandles any chat member in other chats when updated.
onChatJoinRequest($callable)GenericHandles any chat join request.
onException($callable)SpecialThis 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)SpecialThis 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.
fallback($callable)SpecialThis handler if defined will be called if no handler, specific or generic, has been found for the current update.
fallbackOn(string $type, $callable)SpecialThis handler has the same behavior as the previous one, but allows you to put a filter on the type of updates it can handle.

Specific & Special Handlers

onCommand

It's possible to handle to specific commands, also with named parameters:

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();

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');
});

// automatically calls the setMyCommands method
$bot->registerMyCommands();

And the result will be:

commands

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->onText('I want ([0-9]+) portions of (pizza|cake)', function (Nutgram $bot, $amount, $dish) {
$bot->sendMessage("You will get {$amount} portions of {$dish}!");
});

$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\Attributes\MessageTypes;

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

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

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

$bot->run();

You can see all the constants, in the MessageTypes::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('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->onCallbackQueryData('cancel', function (Nutgram $bot) {
$bot->sendMessage('Canceled!');
});

$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('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->onCallbackQueryData('cancel', function (Nutgram $bot) {
$bot->sendMessage('Canceled!');
});

$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\Attributes\UpdateTypes;

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

// define some handlers ...

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

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

$bot->run();

You can see all the constants, in the UpdateTypes::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!
error_log($exception);
$bot->sendMessage('Whoops!');
});

$bot->run();

The onException handler supports also different callbacks based on the exception instance:

use SergiX44\Nutgram\Nutgram;

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

// and exception is thrown...
$bot->onMessage(function (Nutgram $bot) {
if (random_int(0, 1)) {
throw new InvalidArgumentException();
}
throw new Exception('Oh no!');
});

$bot->onException(InvalidArgumentException::class, function (Nutgram $bot, InvalidArgumentException $exception) {
//
});

$bot->onException(Exception::class, function (Nutgram $bot, Exception $exception) {
//
});

$bot->run();

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('Invalid call!', ['chat_id' => null]);
});

$bot->onApiError(function (Nutgram $bot, TelegramException $exception) {
echo $exception->getMessage(); // TelegramException: ...
error_log($exception);
});

$bot->run();

Like the onException, the handler support a regex matching the text returned by the telegram api:

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

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

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

$bot->onApiError('chat not found', function (Nutgram $bot, TelegramException $exception) {
//
});


$bot->onApiError('user(.*)deactivated', function (Nutgram $bot, TelegramException $exception) {
//
});

$bot->run();

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();

Update Helpers

When dealing with updates, sometimes you may need to access data that is nested in the update structure, which can be tedious and produce a lot of boilerplate, since the same objects can often be nested in other objects, depending on the type of update. For this reason, the framework provides a number of support methods to quickly access the most used data, no matter the update type, like this:

use SergiX44\Nutgram\Nutgram;

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

$bot->onCommand('help', function (Nutgram $bot) {
// Get the Message object
$bot->message();

// Access the Chat object
$bot->chat();
});

$bot->onCommand('my_chat', function (Nutgram $bot) {
$bot->sendMessage('Your chat id is ' . $bot->chatId());
});

$bot->run();

Available helpers

MethodReturn typeDescription
update()?UpdateThe current Update object.
chatId()?intThe current chat_id if available, null otherwise.
chat()?ChatThe current Chat if available, null otherwise.
userId()?intThe current from.id if available, null otherwise.
user()?UserThe current User (from Telegram's object) if available, null otherwise.
messageId()?intThe current message.message_id if available, null otherwise.
message()?MessageThe current Message if available, null otherwise.
isCallbackQuery()boolIf the current update contains a callback_query.
callbackQuery()?CallbackQueryThe current CallbackQuery if available, null otherwise.
isInlineQuery()boolIf the current update contains an inline_query.
inlineQuery()?InlineQueryThe current InlineQuery if available, null otherwise.
chosenInlineResult()?ChosenInlineResultThe current ChosenInlineResult if available, null otherwise.
shippingQuery()?ShippingQueryThe current ShippingQuery if available, null otherwise.
isPreCheckoutQuery()boolIf the current update contains a pre_checkout_query.
preCheckoutQuery()?PreCheckoutQueryThe current PreCheckoutQuery if available, null otherwise.
poll()?PollThe current Poll if available, null otherwise.
pollAnswer()?PollAnswerThe current PollAnswer if available, null otherwise.
isMyChatMember()boolIf the current ChatMemberUpdated is in the my_chat_member.
chatMember()?ChatMemberUpdatedThe current ChatMemberUpdated if available, null otherwise.

Persisting data

The framework gives you the ability to store data based on the update context: you can store data as globally or per-user:

use SergiX44\Nutgram\Nutgram;

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

$bot->setGlobalData('mykey', 'Hi!');
$bot->setUserData('mykey', 'Ciao!', $userId);

$value = $bot->getGlobalData('mykey'); // Hi!
$value = $bot->getUserData('mykey', $userId); // Ciao!

// when used inside a context, the $userId can be omitted.
$bot->onCommand('help', function (Nutgram $bot) {
$bot->setUserData('mykey', 'called help!');
$value = $bot->getUserData('mykey'); // called help!
});

$bot->run();
tip

If you need to persist data on disk, be sure to choose an appropriate cache adapter!

Available methods

MethodReturn type
getGlobalData($key, $default = null)The data associated to the $key, if null $default is returned.
setGlobalData($key, $value)bool
deleteGlobalData($key)bool
getUserData($key, ?int $userId = null, $default = null)The data associated to the $key, if null $default is returned.
setUserData($key, $value, ?int $userId = null)bool
deleteUserData($key, ?int $userId = null)bool