Hi friends,
Thx for your great work.
I am new to telegram bot and have a problem.
I want to execute a command on keyboard button press (for example /test command) but i dont know how.
Here is my KeyboardCommand.php file:
namespace Longman\TelegramBot\Commands\UserCommands;
use Longman\TelegramBot\Commands\UserCommand;
use Longman\TelegramBot\Entities\Keyboard;
use Longman\TelegramBot\Request;
/**
* User "/keyboard" command
*/
class KeyboardCommand extends UserCommand
{
/**
* @var string
*/
protected $name = 'keyboard';
/**
* @var string
*/
protected $description = 'Show a custom keyboard with reply markup';
/**
* @var string
*/
protected $usage = '/keyboard';
/**
* @var string
*/
protected $version = '0.2.0';
/**
* Command execute method
*
* @return \Longman\TelegramBot\Entities\ServerResponse
* @throws \Longman\TelegramBot\Exception\TelegramException
*/
public function execute()
{
$keyboard = new Keyboard([
['text' => 'test', '' /* I DONT KNOW HOW TO TELL TO EXECUTE /test COMMAND HERE */]
]);
//Return a random keyboard.
$keyboard = $keyboard
->setResizeKeyboard(true)
->setOneTimeKeyboard(true)
->setSelective(false);
$chat_id = $this->getMessage()->getChat()->getId();
$data = [
'chat_id' => $chat_id,
'text' => 'Press a Button:',
'reply_markup' => $keyboard,
];
return Request::sendMessage($data);
}
}
Thx in advance :)
You have to read message output - use GenericmessageCommand.php for this.
Alternatively you can use Conversation feature to redirect all input to different command (in this case the command that will be handling comparing message content and assigning a command to execute).
Using the Conversation method:
<?php
namespace Longman\TelegramBot\Commands\UserCommands;
use Longman\TelegramBot\Commands\UserCommand;
use Longman\TelegramBot\Conversation;
use Longman\TelegramBot\Entities\Keyboard;
use Longman\TelegramBot\Entities\Update;
use Longman\TelegramBot\Request;
class ExecCommand extends UserCommand
{
protected $name = 'exec';
protected $description = 'Exec command';
protected $usage = '/exec';
protected $version = '1.0.0';
public function execute()
{
$message = $this->getMessage();
$chat = $message->getChat();
$chat_id = $chat->getId();
$user_id = $message->getFrom()->getId();
$text = trim($message->getText(true));
$data = [
'chat_id' => $chat_id,
];
if ($chat->isGroupChat() || $chat->isSuperGroup()) {
$data['reply_markup'] = Keyboard::forceReply(['selective' => true]);
}
$conversation = new Conversation($user_id, $chat_id, $this->getName());
if ($text === '') {
$data['text'] = 'Choose something';
$data['reply_markup'] = new Keyboard(['Need some help', 'Who am I?']);
return Request::sendMessage($data);
}
$update = json_decode($this->update->toJson(), true);
if ($text === 'Need some help') {
$update['message']['text'] = '/help';
$result = (new HelpCommand($this->telegram, new Update($update)))->preExecute();
} elseif ($text === 'Who am I?') {
$update['message']['text'] = '/whoami';
$result = (new WhoamiCommand($this->telegram, new Update($update)))->preExecute();
} else {
$data['text'] = 'Invalid selection...';
return Request::sendMessage($data);
}
$conversation->stop();
return $result;
}
}
@jacklul Is there any cleaner way to execute a command at the moment, that doesn't require the "changing the Update object" hack I always use?
Thx for your reply.
I added the exec command. It displays the keyboard. But when i press Who am i or Need some help buttons it just displays related text but doesnt execute the command.
If i issue /whoami or /help commands they work.
When you type something different instead of using the buttons, do you get Invalid selection...?
Do you have the error log enabled? Any error log entry?
Why not just $this->telegram->executeCommand("xxx")?
Hmm, was trying that but it kept on using the current Update object which has the wrong text in it, which is what gets used to execute.
Will need to try this again and dig deeper 馃憤
@noplanman, no I dont get Invalid selection.
I have enabled log with this commands:
Longman\TelegramBot\TelegramLog::initErrorLog(__DIR__ . '/' . $BOT_NAME . '_error.log');
Longman\TelegramBot\TelegramLog::initDebugLog(__DIR__ . '/' . $BOT_NAME . '_debug.log');
But there is no error.
Oh, just noticed that you don't use the database!
Try renaming the execute() method to executeNoDb().
@noplanman, the execute() method works and the keyboard appears, but the buttons doesnot work.
with executeNoDb() method the keyboard doesnot appear at all.
@jacklul
Try this, does it work for you? The help button doesn't execute /help properly for me.
(Using the main command from the top, replacing the if condition with this:
$result = Request::emptyResponse();
if ($text === 'Need some help') {
$this->getTelegram()->executeCommand('help');
} elseif ($text === 'Who am I?') {
$this->getTelegram()->executeCommand('whoami');
} else {
...
}
Maybe it works for some commands, but it's not a clean solution for commands that depend on Update data.
@rahimasgari I just realised, you can only use conversations with a database.
So the only option you have, without a database, is to use GenericmessageCommand.php and put everything in there:
protected $need_mysql = false;
public function execute()
{
$message = $this->getMessage();
$text = trim($message->getText(true));
$update = json_decode($this->update->toJson(), true);
if ($text === 'Need some help') {
$update['message']['text'] = '/help';
return (new HelpCommand($this->telegram, new Update($update)))->preExecute();
}
if ($text === 'Who am I?') {
$update['message']['text'] = '/whoami';
return (new WhoamiCommand($this->telegram, new Update($update)))->preExecute();
}
return Request::emptyResponse();
}
If anybody, at any time, writes either Need some help or Who am I?, the respective commands are called. This is because all messages go through this class.
@noplanman It executes the command correctly in my case.
return (new HelpCommand($this->telegram, new Update($update)))->preExecute();
Didn't executeCommand previously accept Update object? That could really simplify life for people if we could make exact same functionality already in executeCommand.
Didn't
executeCommandpreviously accept Update object?
Not that I know of.
But, if you look here, you'll see that the current Update object is used automatically, if none is provided by the method I used above.
And for this exact reason, just using $telegram->executeCommand(...) doesn't work, at least for me.
But why does it work for you? So strange 馃槙
So this is my final code. but it doesnt work yet. (keyboard is displayed but buttons doesnt work)
<?php
namespace Longman\TelegramBot\Commands\SystemCommands;
use Longman\TelegramBot\Commands\SystemCommand;
use Longman\TelegramBot\Entities\Keyboard;
use Longman\TelegramBot\Entities\Update;
use Longman\TelegramBot\Request;
class ExecCommand extends SystemCommand
{
protected $name = 'exec';
protected $description = 'Exec command';
protected $usage = '/exec';
protected $version = '1.0.0';
protected $need_mysql = false;
public function execute()
{
$message = $this->getMessage();
$chat = $message->getChat();
$chat_id = $chat->getId();
$user_id = $message->getFrom()->getId();
$text = trim($message->getText(true));
$data = [
'chat_id' => $chat_id,
];
if ($chat->isGroupChat() || $chat->isSuperGroup()) {
$data['reply_markup'] = Keyboard::forceReply(['selective' => true]);
}
if ($text === '') {
$data['text'] = 'Choose something';
$data['reply_markup'] = new Keyboard(['Need some help', 'Who am I?']);
return Request::sendMessage($data);
}
$update = json_decode($this->update->toJson(), true);
if ($text === 'Need some help') {
$update['message']['text'] = '/help';
return (new HelpCommand($this->telegram, new Update($update)))->preExecute();
}
if ($text === 'Who am I?') {
$update['message']['text'] = '/whoami';
return (new WhoamiCommand($this->telegram, new Update($update)))->preExecute();
}
return Request::emptyResponse();
}
}
Instead of SystemCommand, it must be UserCommand!
System commands are special commands that don't get called by users directly.
At first I used UserCommand and then i changed it to SystemCommand (according to the GenericmessageCommand.php).
At last i decided to enable mysql to make it work and it worked perfectly.
I think that it has a problem not using db.
Thx for your replies. :)
I've tested it without a DB and it works.
I think there is a mixup of commands.
The following works for me:
GenericmessageCommand.php
<?php
namespace Longman\TelegramBot\Commands\SystemCommands;
use Longman\TelegramBot\Commands\SystemCommand;
use Longman\TelegramBot\Commands\UserCommands\HelpCommand;
use Longman\TelegramBot\Commands\UserCommands\WhoamiCommand;
use Longman\TelegramBot\Entities\Update;
use Longman\TelegramBot\Request;
class GenericmessageCommand extends SystemCommand
{
protected $name = 'Genericmessage';
protected $description = 'Handle generic message';
protected $version = '1.0.0';
public function execute()
{
$text = trim($this->getMessage()->getText(true));
$update = json_decode($this->update->toJson(), true);
if ($text === 'Need some help') {
$update['message']['text'] = '/help';
return (new HelpCommand($this->telegram, new Update($update)))->preExecute();
}
if ($text === 'Who am I?') {
$update['message']['text'] = '/whoami';
return (new WhoamiCommand($this->telegram, new Update($update)))->preExecute();
}
return Request::emptyResponse();
}
}
ExecCommand.php
<?php
namespace Longman\TelegramBot\Commands\UserCommands;
use Longman\TelegramBot\Commands\UserCommand;
use Longman\TelegramBot\Entities\Keyboard;
use Longman\TelegramBot\Request;
class ExecCommand extends UserCommand
{
protected $name = 'exec';
protected $description = 'Exec command';
protected $usage = '/exec';
protected $version = '1.0.0';
public function execute()
{
$data = [
'chat_id' => $this->getMessage()->getChat()->getId(),
'text' => 'Choose something',
'reply_markup' => new Keyboard(['Need some help', 'Who am I?']),
];
return Request::sendMessage($data);
}
}
@rahimasgari Did you get this to work, can I close here?
this works. I have tested with my bot.
if ($text === 'Need some help') {
$update['message']['text'] = '/help';
return (new HelpCommand($this->telegram, new Update($update)))->preExecute();
}
if ($text === 'Who am I?') {
$update['message']['text'] = '/whoami';
return (new WhoamiCommand($this->telegram, new Update($update)))->preExecute();
}
is it better if the second if replaced by elseif ? so the checking will stop if condition is met.
@arkhub That's not necessary, because of the return statement.
The second if never gets called if the first one is true.
oh you're right, didn't see that one.
$update = json_decode($this->update->toJson(), true);
$update['message']['text'] = '/signup';
return (new SignupCommand($this->telegram, new Update($update)))->preExecute();
it does not work for me!
SignupCommand is an survey command.
You can also extend Telegram class and define a new function to ease executing commands
public function executeCommandUpdate($command, \Longman\TelegramBot\Entities\Update $update) {
$this->update = $update;
return $this->executeCommand($command);
}
@noplanman I'm so sorry for necroposting, but!
I tried to use that:
GenericmessageCommand.php
public function execute()
{
$text = trim($this->getMessage()->getText(true));
if ($text === '馃敊 Balance') {
$update['message']['text'] = '/balance';
return (new BalanceCommand($this->telegram, new Update($update)))->preExecute();
}
if ($text === '馃敊 To start') {
$update['message']['text'] = '/start';
return (new StartCommand($this->telegram, new Update($update)))->preExecute();
}
return Request::emptyResponse();
}
And after I click at 馃敊 Balance button nothing happens and I've got an error:
PHP Fatal error: Uncaught Error: Call to a member function getId() on null in /var/www/www-root/data/www/_/Commands/UserCommands/BalanceCommand.php:42\nStack trace:
#0 /var/www/www-root/data/www/_/vendor/longman/telegram-bot/src/Commands/Command.php(173): Longman\\TelegramBot\\Commands\\UserCommands\\BalanceCommand->execute()
#1 /var/www/www-root/data/www/s_/Commands/SystemCommands/GenericmessageCommand.php(48): Longman\\TelegramBot\\Commands\\Command->preExecute()
#2 /var/www/www-root/data/www/_/vendor/longman/telegram-bot/src/Commands/Command.php(173): Longman\\TelegramBot\\Commands\\SystemCommands\\GenericmessageCommand->execute()
#3 /var/www/www-root/data/www/_/vendor/longman/telegram-bot/src/Telegram.php(494): Longman\\TelegramBot\\Commands\\Command->preExecute()
#4 /var/www/www-root/data/www/_/vendor/longman/telegram-bot/src/Telegram.php(462): Longman\\TelegramBot\\Telegram->executeCommand('genericmessage')
#5 /var/www/www-root/dat in /var/www/www-root/data/www/_/Commands/UserCommands/BalanceCommand.php on line 42
And here is 42 line in BalanceCommand:
$chat_id = $chat->getId();
For 馃敊 To start button I've got same problem.
Thanks in advance!
You need to add this too, to get the correct Update object:
$update = json_decode($this->getUpdate()->toJson(), true);
Otherwise it's just passing a very incomplete array!
@noplanman oh, my bad :(
Thanks for your great work!
Most helpful comment
You need to add this too, to get the correct Update object:
Otherwise it's just passing a very incomplete array!