Completed
Push — master ( 23095d...54d687 )
by Danilo
02:12
created

BaseBot::getUpdatesLocal()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 59
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 21
nc 8
nop 2
dl 0
loc 59
rs 8.7117
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace PhpBotFramework\Core;
4
5
use PhpBotFramework\Exceptions\BotException;
6
7
/**
8
 * \class Bot Bot
9
 * \brief Bot class to handle updates and commandes.
10
 * \details Class Bot to handle task like api request, or more specific api function(sendMessage, editMessageText, etc).
11
 * Usage example in webhook.php
12
 *
13
 */
14
class BaseBot extends CoreBot {
15
16
    /**
17
     * \addtogroup Core Core(Internal)
18
     * @{
19
     */
20
21
    /** \brief Is the bot using webhook? */
22
    protected $_is_webhook;
23
24
    /**
25
     * \brief Construct an empty base bot.
26
     * \details Construct a base bot that can handle updates.
27
     */
28
    public function __construct(string $token) {
29
30
        // Parent constructor
31
        parent::__construct($token);
32
33
        // Add alias for entity classes
34
        class_alias('PhpBotFramework\Entities\Message', 'Message');
35
        class_alias('PhpBotFramework\Entities\CallbackQuery', 'CallbackQuery');
36
        class_alias('PhpBotFramework\Entities\InlineQuery', 'InlineQuery');
37
        class_alias('PhpBotFramework\Entities\ChosenInlineResult', 'ChosenInlineResult');
38
        class_alias('Message', 'EditedMessage');
39
        class_alias('Message', 'ChannelPost');
40
        class_alias('Message', 'EditedChannelPost');
41
42
    }
43
44
    /** @} */
45
46
    /**
47
     * \addtogroup Bot
48
     * @{
49
     */
50
51
    /**
52
     * \brief Get update and process it.
53
     * \details Call this method if you are using webhook.
54
     * It will get update from php::\input, check it and then process it using processUpdate.
55
     */
56
    public function processWebhookUpdate() {
57
58
        $this->_is_webhook = true;
59
60
        // If CommandHandler trait is used and initCommands method exists
61
        if (method_exists($this, 'initCommands')) {
62
63
            $this->initCommands();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class PhpBotFramework\Core\BaseBot as the method initCommands() does only exist in the following sub-classes of PhpBotFramework\Core\BaseBot: PhpBotFramework\Bot. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
64
65
        } 
66
67
        $this->processUpdate(json_decode(file_get_contents('php://input'), true));
68
69
    }
70
71
    /**
72
     * \brief Get updates received by the bot, and hold the offset in $offset.
73
     * \details Get the update_id of the first update to parse, set it in $offset and
74
     * then it start an infinite loop where it processes updates and keep $offset on the update_id of the last update received.
75
     * Each processUpdate() method call is surrounded by a try/catch.
76
     * @see getUpdates
77
     * @param $limit <i>Optional</i>. Limits the number of updates to be retrieved. Values between 1—100 are accepted.
78
     * @param $timeout <i>Optional</i>. Timeout in seconds for long polling.
79
     */
80
    public function getUpdatesLocal(int $limit = 100, int $timeout = 60) {
81
82
        $update = [];
0 ignored issues
show
Unused Code introduced by
$update is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
83
84
        // While there aren't updates to process
85
        do {
86
87
            // Get updates from telegram
88
            $update = $this->getUpdates(0, 1);
89
90
            // While in the array received there aren't updates
91
        } while (empty($update));
92
93
        // Set the offset to the first update recevied
94
        $offset = $update[0]['update_id'];
95
96
        $update = null;
97
98
        // If CommandHandler trait is used and initCommands method exists
99
        if (method_exists($this, 'initCommands')) {
100
101
            $this->initCommands();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class PhpBotFramework\Core\BaseBot as the method initCommands() does only exist in the following sub-classes of PhpBotFramework\Core\BaseBot: PhpBotFramework\Bot. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
102
103
        }
104
105
        // Process all updates
106
        while (true) {
107
108
            // Set parameter for the url call
109
            $parameters = [
110
                'offset' => $offset,
111
                'limit' => $limit,
112
                'timeout' => $timeout
113
            ];
114
115
            $updates = $this->exec_curl_request($this->_api_url . 'getUpdates?' . http_build_query($parameters));
116
117
            // Parse all update to receive
118
            foreach ($updates as $key => $update) {
119
120
                try {
121
122
                    // Process one at a time
123
                    $this->processUpdate($update);
124
125
                } catch (BotException $e) {
126
127
                    echo $e->getMessage();
128
129
                }
130
131
            }
132
133
            // Update the offset
134
            $offset += sizeof($updates);
135
136
        }
137
138
    }
139
140
    /** @} */
141
142
    /**
143
     * \addtogroup Core Core(Internal)
144
     * @{
145
     */
146
147
    /**
148
     * \brief Dispatch each update to the right method (processMessage, processCallbackQuery, etc).
149
     * \details Set $chat_id for each update, $text, $data and $query are set for each update that contains them.
150
     * @param $update Reference to the update received.
151
     * @return The id of the update processed.
152
     */
153
    protected function processUpdate(array $update) : int {
154
155
        static $updates_type = ['message' => 'Message',
156
            'callback_query' => 'CallbackQuery',
157
            'inline_query' => 'InlineQuery',
158
            'channel_post' => 'ChannelPost',
159
            'edited_message' => 'EditedMessage',
160
            'edited_channel_post' => 'EditedChannelPost',
161
            'chosen_inline_result' => 'ChosenInlineResult'];
162
163
        foreach ($updates_type as $offset => $class) {
164
165
            if (isset($update[$offset])) {
166
167
                $object = new $class($update[$offset]);
168
169
                $this->_chat_id = $object->getChatID();
170
171
                if (method_exists($object, 'getBotParameter')) {
172
173
                    $var = $object->getBotParameter();
174
                    $this->{$var['var']} = $var['id'];
175
176
                }
177
178
                $this->{"process$class"}($object);
179
180
                return $update['update_id'];
181
182
            }
183
184
        }
185
186
    }
187
188
    /** @} */
189
190
    /**
191
     * \addtogroup Bot Bot
192
     * @{
193
     */
194
195
    /**
196
     * \brief Called every message received by the bot.
197
     * \details Override it to script the bot answer for each message.
198
     * <code>$chat_id</code> and <code>$text</code>, if the message contains text(use getMessageText() to access it), set inside of this function.
199
     * @param $message Reference to the message received.
200
     */
201
    protected function processMessage($message) {
0 ignored issues
show
Unused Code introduced by
The parameter $message is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
202
203
    }
204
205
    /**
206
     * \brief Called every callback query received by the bot.
207
     * \details Override it to script the bot answer for each callback.
208
     * <code>$chat_id</code> and <code>$data</code>, if set in the callback query(use getCallbackData() to access it) set inside of this function.
209
     * @param $callback_query Reference to the callback query received.
210
     */
211
    protected function processCallbackQuery($callback_query) {
0 ignored issues
show
Unused Code introduced by
The parameter $callback_query is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
212
213
    }
214
215
    /**
216
     * \brief Called every inline query received by the bot.
217
     * \details Override it to script the bot answer for each inline query.
218
     * $chat_id and $query(use getInlineQuery() to access it) set inside of this function.
219
     * @param $inline_query Reference to the inline query received.
220
     */
221
    protected function processInlineQuery($inline_query) {
0 ignored issues
show
Unused Code introduced by
The parameter $inline_query is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
222
223
    }
224
225
    /**
226
     * \brief Called every chosen inline result received by the bot.
227
     * \details Override it to script the bot answer for each chosen inline result.
228
     * <code>$chat_id</code> set inside of this function.
229
     * @param $chosen_inline_result Reference to the chosen inline result received.
230
     */
231
    protected function processChosenInlineResult($chosen_inline_result) {
0 ignored issues
show
Unused Code introduced by
The parameter $chosen_inline_result is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
232
233
    }
234
235
    /**
236
     * \brief Called every chosen edited message received by the bot.
237
     * \details Override it to script the bot answer for each edited message.
238
     * <code>$chat_id</code> set inside of this function.
239
     * @param $edited_message The message edited by the user.
240
     */
241
    protected function processEditedMessage($edited_message) {
0 ignored issues
show
Unused Code introduced by
The parameter $edited_message is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
242
243
    }
244
245
    /**
246
     * \brief Called every new post in the channel where the bot is in.
247
     * \details Override it to script the bot answer for each post sent in a channel.
248
     * <code>$chat_id</code> set inside of this function.
249
     * @param $post The message sent in the channel.
250
     */
251
    protected function processChannelPost($post) {
0 ignored issues
show
Unused Code introduced by
The parameter $post is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
252
253
    }
254
255
    /**
256
     * \brief Called every time a post get edited in the channel where the bot is in.
257
     * \details Override it to script the bot answer for each post edited  in a channel.
258
     * <code>$chat_id</code> set inside of this function.
259
     * @param $post The message edited in the channel.
260
     */
261
    protected function processEditedChannelPost($edited_post) {
0 ignored issues
show
Unused Code introduced by
The parameter $edited_post is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
262
263
    }
264
265
    /** @} */
266
267
}
268