php-telegram-bot / core

PHP Telegram Bot based on the official Telegram Bot API
MIT License
3.88k stars 953 forks source link

How to get poll answer from user? #1152

Closed derived-coder closed 3 years ago

derived-coder commented 3 years ago

❓ Support Question

How can I get back the answer from a poll that I have posted?

I am using atm. Request::sendPoll and it is working. But how can I get the answer from the user?

Required Information

? !
Operating system linux
PHP Telegram Bot version 0.64
PHP version php-7.3.25
MySQL version / none
Update Method Webhook
Self-signed certificate yes
RAW update (if available) {...}
noplanman commented 3 years ago

The poll responses can be picked up by creating a custom PollanswerCommand class that extends SystemCommand or by adding some code to your custom GenericCommand::execute method, like if ($poll_answer = $this->getUpdate()->getPollAnswer()).

Hope that helps. Just ask again if you need more info 👍

derived-coder commented 3 years ago

@noplanman okay, this here is my current PollCommand.php

/**
 * User "/poll" command
 *
 * Creates a quiz
 */

namespace Longman\TelegramBot\Commands\UserCommands;

use Longman\TelegramBot\Commands\UserCommand;
use Longman\TelegramBot\Entities\ServerResponse;
use Longman\TelegramBot\Exception\TelegramException;
use Longman\TelegramBot\Request;

class PollCommand extends UserCommand
{
    /**
     * @var string
     */
    protected $name = 'poll';

    /**
     * @var string
     */
    protected $description = 'Poll for quizes';

    /**
     * @var string
     */
    protected $usage = '/poll <@user>';

    /**
     * @var string
     */
    protected $version = '1.2.0';

    /**
     * Main command execution
     *
     * @return ServerResponse
     * @throws TelegramException
     */
    public function execute(): ServerResponse
    {

        $message = $this->getMessage();
        $text    = $message->getText(true);

        $sender = '@' . $message->getFrom()->getUsername();

        if ($poll_answer = $this->getUpdate()->getPollAnswer())
        {
            $poll_answer_poll_id = $poll_answer->getPollId(); // how to check the correct poll ID???
            $poll_options_id = $poll_answer->option_ids();

            if ($poll_options_id[0] == 0){
                return $this->replyToChat('
               **Correct Answer!**
                ', ['parse_mode' => 'markdown',]);
            } else {
                return $this->replyToChat('
               **Wrong Answer!**
                ', ['parse_mode' => 'markdown',]);
            }
        } 
        else{

            $options =  array("Mission Impossible 5","Oblivion", "Top Gun 2");

            return Request::sendPoll([
                'chat_id' => $message->getFrom()->getId(),
                'question' => "What is the latest movie from Tom Cruise?",
                'options'   => json_encode($options),
                'type' => 'quiz',
                'correct_option_id' => "0",
                'open_period' => 2
            ]);
        }
    }
}

But when I answer the poll, no message is send back to the user. What is wrong here?

PS: How can I compare that this answer is the one for the correct question? PPS: What is the difference between SystemCommand and UserCommand?

derived-coder commented 3 years ago

@noplanman Any update here? don't know how to continue with this.

noplanman commented 3 years ago

What is the difference between SystemCommand and UserCommand?

System commands cannot be executed by users and are used internally.

Right, you need to separate your code here, as the incoming request from a user responding to the poll goes to the PollanswerCommand (not PollCommand).

So create a new PollanswerCommand extends SystemCommand class and put your code for checking the answer in there.

How can I compare that this answer is the one for the correct question?

I'll have a look tomorrow how best to do this, bed time now 😴

derived-coder commented 3 years ago

@noplanman see my code, I do not get any reply:

<?php

/**
 * This file is part of the PHP Telegram Bot example-bot package.
 * https://github.com/php-telegram-bot/example-bot/
 *
 * (c) PHP Telegram Bot Team
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/**
 * Poll Answer command
 *
 *
 * @see PollAnswerCommand.php
 */

namespace Longman\TelegramBot\Commands\SystemCommands;

use Longman\TelegramBot\Commands\SystemCommand;
use Longman\TelegramBot\Entities\ServerResponse;

class PollAnswerCommand extends SystemCommand
{
    /**
     * @var string
     */
    protected $name = 'pollanswer';

    /**
     * @var string
     */
    protected $description = 'Read the answer of a poll';

    /**
     * @var string
     */
    protected $version = '1.2.0';

    /**
     * Main command execution
     *
     * @return ServerResponse
     * @throws \Exception
     */
    public function execute(): ServerResponse
    {

        if ($poll_answer = $this->getUpdate()->getPollAnswer())
        {
            $poll_answer_poll_id = $poll_answer->getPollId();
            $poll_options_id = $poll_answer->option_ids();

            if ($poll_options_id[0] == 0){
                return $this->replyToChat('
               **Correct Answer!**
                ', ['parse_mode' => 'markdown',]);
            } else {
                return $this->replyToChat('
               **Wrong Answer!**
                ', ['parse_mode' => 'markdown',]);
            }
        } 
    }
}

I mean how, can i general function executed for my specific poll answer. What I am looking for is some kind of register, for this poll, when the answer comes back: please execute following code.

noplanman commented 3 years ago

Try something like this, which you might need to adapt to your use-case:

    public function execute(): ServerResponse
    {
        if ($poll_answer = $this->getUpdate()->getPollAnswer()) {
            $poll_id         = $poll_answer->getPollId();
            $poll_option_ids = $poll_answer->getOptionIds();

            $query = DB::getPdo()->prepare('
                SELECT `correct_option_id`
                FROM `poll`
                WHERE `id` = ?
            ');
            $query->execute([$poll_id]);

            $correct_answer = $query->fetchColumn();
            if ($poll_option_ids[0] === $correct_answer) {
                return $this->replyToChat('**Correct Answer!**', ['parse_mode' => 'markdown']);
            }

            return $this->replyToChat('**Wrong Answer!**', ['parse_mode' => 'markdown']);
        }
    }
derived-coder commented 3 years ago

@noplanman sorry, but this does not help.

1) I need to clarify here something: I do not get any answer when I choose in option on the poll. This needs to be solved first. When I press the button. How do I get a reply, whether it was the correct answer or not? Even when I hard-code the answer in the code. Like you can see in my example code.

2) This DB query is possible approach when you have stored your poll in DB. But how do I get the pollID when I post the poll? This needs to be solved 2nd: So how do I get from this the poll the ID?

 return Request::sendPoll([
                'chat_id' => $message->getFrom()->getId(),
                'question' => "What is the latest movie from Tom Cruise?",
                'options'   => json_encode($options),
                'type' => 'quiz',
                'correct_option_id' => "0",
                'open_period' => 2
            ]);

PS: This is how it is done in python: https://stackoverflow.com/questions/61090856/getting-the-poll-result-from-send-poll-telegram-bot-with-python maybe you get an idea how to do this with your library?

noplanman commented 3 years ago

When sending a poll, you get a ServerResponse entity returned. From that you can fetch the result, which is a Message entity that contains the Poll entity, which in turn contains the ID 👍

so:

$response = Request::sendPoll(...);

// Check that the request was successful and that we can access the Poll entity.
if ($response->isOk() && $poll = $response->getResult()->getPoll()) {
    // Here you can access all info of $poll, which is a Poll entity.
    $poll_id = $poll->getId();
}

return $response;

Hope that helps 😊

P.S. Note that you don't need to json_encode the options, you can simply pass an array. Internally it gets converted before sending the request 👍

derived-coder commented 3 years ago

@noplanman Okay this is the answer to problem 2.

What about problem number 1? How do I get the answer?

noplanman commented 3 years ago

@derived-coder I didn't have time at the moment of my response, apologies!

Instead of using PollanswerCommand.php, try with GenericCommand.php using this in your execute method:

public function execute(): ServerResponse
{
    if ($poll_answer = $this->getUpdate()->getPollAnswer()) {
        // Basically what was in your PollanswerCommand:execute
    }
}

I hope that works. Otherwise there seems to be some other problem here, which we might need to resolve in a private Telegram chat. Feel free to get in touch! https://t.me/noplanman

derived-coder commented 3 years ago

that is the working code to get the answer:

 public function execute(): ServerResponse
    {
        if ($poll_answer = $this->getUpdate()->getPollAnswer()) {
            $user_id         = $poll_answer->getUser()->getId();
            $poll_option_ids = $poll_answer->getOptionIds();

            $correct_answer = 0;

            $text = '**Wrong Answer!**';

            if ($poll_option_ids[0] === $correct_answer) {
                $text = '**Correct Answer!**';
            }

            return Request::sendMessage([
                'chat_id'    => $user_id,
                'text'       => $text,
                'parse_mode' => 'markdown',
            ]);
        }
    }
devaka commented 1 year ago

Hey derived-coder! Please write in details how did you solve the problem and got answer from poll? Is your code used in PollCommand.php, PollanswerCommand.php or GenericCommand.php? I used various methods and no results yet.

that is the working code to get the answer:

 public function execute(): ServerResponse
    {
        if ($poll_answer = $this->getUpdate()->getPollAnswer()) {
            $user_id         = $poll_answer->getUser()->getId();
            $poll_option_ids = $poll_answer->getOptionIds();

            $correct_answer = 0;

            $text = '**Wrong Answer!**';

            if ($poll_option_ids[0] === $correct_answer) {
                $text = '**Correct Answer!**';
            }

            return Request::sendMessage([
                'chat_id'    => $user_id,
                'text'       => $text,
                'parse_mode' => 'markdown',
            ]);
        }
    }
svyatoslav-reshetnikov commented 1 year ago

Hello! Is there any update about @devaka question? I'm struggling with getting response from poll. Have the same question about place where I have to put this code.

noplanman commented 1 year ago

@devaka @svyatoslav-reshetnikov

The code should go in GenericmessageCommand.php, as the poll answers come through as a generic message.