Passed
Push — master ( 9ca615...b6ea35 )
by Armando
02:47
created

Command::executeNoDb()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
1
<?php
2
3
/**
4
 * This file is part of the TelegramBot package.
5
 *
6
 * (c) Avtandil Kikabidze aka LONGMAN <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Longman\TelegramBot\Commands;
13
14
use Longman\TelegramBot\DB;
15
use Longman\TelegramBot\Entities\CallbackQuery;
16
use Longman\TelegramBot\Entities\ChosenInlineResult;
17
use Longman\TelegramBot\Entities\InlineQuery;
18
use Longman\TelegramBot\Entities\Message;
19
use Longman\TelegramBot\Entities\Payments\PreCheckoutQuery;
20
use Longman\TelegramBot\Entities\Payments\ShippingQuery;
21
use Longman\TelegramBot\Entities\Poll;
22
use Longman\TelegramBot\Entities\ServerResponse;
23
use Longman\TelegramBot\Entities\Update;
24
use Longman\TelegramBot\Exception\TelegramException;
25
use Longman\TelegramBot\Request;
26
use Longman\TelegramBot\Telegram;
27
28
/**
29
 * Class Command
30
 *
31
 * Base class for commands. It includes some helper methods that can fetch data directly from the Update object.
32
 *
33
 * @method Message             getMessage()            Optional. New incoming message of any kind — text, photo, sticker, etc.
34
 * @method Message             getEditedMessage()      Optional. New version of a message that is known to the bot and was edited
35
 * @method Message             getChannelPost()        Optional. New post in the channel, can be any kind — text, photo, sticker, etc.
36
 * @method Message             getEditedChannelPost()  Optional. New version of a post in the channel that is known to the bot and was edited
37
 * @method InlineQuery         getInlineQuery()        Optional. New incoming inline query
38
 * @method ChosenInlineResult  getChosenInlineResult() Optional. The result of an inline query that was chosen by a user and sent to their chat partner.
39
 * @method CallbackQuery       getCallbackQuery()      Optional. New incoming callback query
40
 * @method ShippingQuery       getShippingQuery()      Optional. New incoming shipping query. Only for invoices with flexible price
41
 * @method PreCheckoutQuery    getPreCheckoutQuery()   Optional. New incoming pre-checkout query. Contains full information about checkout
42
 * @method Poll                getPoll()               Optional. New poll state. Bots receive only updates about polls, which are sent or stopped by the bot
43
 */
44
abstract class Command
45
{
46
    /**
47
     * Auth level for user commands
48
     */
49
    public const AUTH_USER = 'User';
50
51
    /**
52
     * Auth level for system commands
53
     */
54
    public const AUTH_SYSTEM = 'System';
55
56
    /**
57
     * Auth level for admin commands
58
     */
59
    public const AUTH_ADMIN = 'Admin';
60
61
    /**
62
     * Telegram object
63
     *
64
     * @var Telegram
65
     */
66
    protected $telegram;
67
68
    /**
69
     * Update object
70
     *
71
     * @var Update
72
     */
73
    protected $update;
74
75
    /**
76
     * Name
77
     *
78
     * @var string
79
     */
80
    protected $name = '';
81
82
    /**
83
     * Description
84
     *
85
     * @var string
86
     */
87
    protected $description = 'Command description';
88
89
    /**
90
     * Usage
91
     *
92
     * @var string
93
     */
94
    protected $usage = 'Command usage';
95
96
    /**
97
     * Show in Help
98
     *
99
     * @var bool
100
     */
101
    protected $show_in_help = true;
102
103
    /**
104
     * Version
105
     *
106
     * @var string
107
     */
108
    protected $version = '1.0.0';
109
110
    /**
111
     * If this command is enabled
112
     *
113
     * @var bool
114
     */
115
    protected $enabled = true;
116
117
    /**
118
     * If this command needs mysql
119
     *
120
     * @var bool
121
     */
122
    protected $need_mysql = false;
123
124
    /*
125
    * Make sure this command only executes on a private chat.
126
    *
127
    * @var bool
128
    */
129
    protected $private_only = false;
130
131
    /**
132
     * Command config
133
     *
134
     * @var array
135
     */
136
    protected $config = [];
137
138
    /**
139
     * Constructor
140
     *
141
     * @param Telegram    $telegram
142
     * @param Update|null $update
143
     */
144 16
    public function __construct(Telegram $telegram, ?Update $update = null)
145
    {
146 16
        $this->telegram = $telegram;
147 16
        if ($update !== null) {
148
            $this->setUpdate($update);
149
        }
150 16
        $this->config = $telegram->getCommandConfig($this->name);
151 16
    }
152
153
    /**
154
     * Set update object
155
     *
156
     * @param Update $update
157
     *
158
     * @return Command
159
     */
160 1
    public function setUpdate(Update $update): Command
161
    {
162 1
        $this->update = $update;
163
164 1
        return $this;
165
    }
166
167
    /**
168
     * Pre-execute command
169
     *
170
     * @return ServerResponse
171
     * @throws TelegramException
172
     */
173
    public function preExecute(): ServerResponse
174
    {
175
        if ($this->need_mysql && !($this->telegram->isDbEnabled() && DB::isDbConnected())) {
176
            return $this->executeNoDb();
177
        }
178
179
        if ($this->isPrivateOnly() && $this->removeNonPrivateMessage()) {
180
            $message = $this->getMessage();
181
182
            if ($user = $message->getFrom()) {
183
                return Request::sendMessage([
184
                    'chat_id'    => $user->getId(),
185
                    'parse_mode' => 'Markdown',
186
                    'text'       => sprintf(
187
                        "/%s command is only available in a private chat.\n(`%s`)",
188
                        $this->getName(),
189
                        $message->getText()
190
                    ),
191
                ]);
192
            }
193
194
            return Request::emptyResponse();
195
        }
196
197
        return $this->execute();
198
    }
199
200
    /**
201
     * Execute command
202
     *
203
     * @return ServerResponse
204
     * @throws TelegramException
205
     */
206
    abstract public function execute(): ServerResponse;
207
208
    /**
209
     * Execution if MySQL is required but not available
210
     *
211
     * @return ServerResponse
212
     * @throws TelegramException
213
     */
214
    public function executeNoDb(): ServerResponse
215
    {
216
        return $this->replyToChat('Sorry no database connection, unable to execute "' . $this->name . '" command.');
217
    }
218
219
    /**
220
     * Get update object
221
     *
222
     * @return Update|null
223
     */
224 2
    public function getUpdate(): ?Update
225
    {
226 2
        return $this->update;
227
    }
228
229
    /**
230
     * Relay any non-existing function calls to Update object.
231
     *
232
     * This is purely a helper method to make requests from within execute() method easier.
233
     *
234
     * @param string $name
235
     * @param array  $arguments
236
     *
237
     * @return Command
238
     */
239 1
    public function __call(string $name, array $arguments)
240
    {
241 1
        if ($this->update === null) {
242 1
            return null;
243
        }
244 1
        return call_user_func_array([$this->update, $name], $arguments);
245
    }
246
247
    /**
248
     * Get command config
249
     *
250
     * Look for config $name if found return it, if not return $default.
251
     * If $name is not set return all set config.
252
     *
253
     * @param string|null $name
254
     * @param mixed       $default
255
     *
256
     * @return mixed
257
     */
258 3
    public function getConfig(?string $name = null, $default = null)
259
    {
260 3
        if ($name === null) {
261 3
            return $this->config;
262
        }
263 1
        return $this->config[$name] ?? $default;
264
    }
265
266
    /**
267
     * Get telegram object
268
     *
269
     * @return Telegram
270
     */
271 1
    public function getTelegram(): Telegram
272
    {
273 1
        return $this->telegram;
274
    }
275
276
    /**
277
     * Get usage
278
     *
279
     * @return string
280
     */
281 1
    public function getUsage(): string
282
    {
283 1
        return $this->usage;
284
    }
285
286
    /**
287
     * Get version
288
     *
289
     * @return string
290
     */
291 1
    public function getVersion(): string
292
    {
293 1
        return $this->version;
294
    }
295
296
    /**
297
     * Get description
298
     *
299
     * @return string
300
     */
301 1
    public function getDescription(): string
302
    {
303 1
        return $this->description;
304
    }
305
306
    /**
307
     * Get name
308
     *
309
     * @return string
310
     */
311 3
    public function getName(): string
312
    {
313 3
        return $this->name;
314
    }
315
316
    /**
317
     * Get Show in Help
318
     *
319
     * @return bool
320
     */
321 1
    public function showInHelp(): bool
322
    {
323 1
        return $this->show_in_help;
324
    }
325
326
    /**
327
     * Check if command is enabled
328
     *
329
     * @return bool
330
     */
331 1
    public function isEnabled(): bool
332
    {
333 1
        return $this->enabled;
334
    }
335
336
    /**
337
     * If this command is intended for private chats only.
338
     *
339
     * @return bool
340
     */
341
    public function isPrivateOnly(): bool
342
    {
343
        return $this->private_only;
344
    }
345
346
    /**
347
     * If this is a SystemCommand
348
     *
349
     * @return bool
350
     */
351 2
    public function isSystemCommand(): bool
352
    {
353 2
        return ($this instanceof SystemCommand);
354
    }
355
356
    /**
357
     * If this is an AdminCommand
358
     *
359
     * @return bool
360
     */
361 2
    public function isAdminCommand(): bool
362
    {
363 2
        return ($this instanceof AdminCommand);
364
    }
365
366
    /**
367
     * If this is a UserCommand
368
     *
369
     * @return bool
370
     */
371 2
    public function isUserCommand(): bool
372
    {
373 2
        return ($this instanceof UserCommand);
374
    }
375
376
    /**
377
     * Delete the current message if it has been called in a non-private chat.
378
     *
379
     * @return bool
380
     */
381
    protected function removeNonPrivateMessage(): bool
382
    {
383
        $message = $this->getMessage() ?: $this->getEditedMessage();
384
385
        if ($message) {
0 ignored issues
show
introduced by
$message is of type Longman\TelegramBot\Entities\Message, thus it always evaluated to true.
Loading history...
386
            $chat = $message->getChat();
387
388
            if (!$chat->isPrivateChat()) {
389
                // Delete the falsely called command message.
390
                Request::deleteMessage([
391
                    'chat_id'    => $chat->getId(),
392
                    'message_id' => $message->getMessageId(),
393
                ]);
394
395
                return true;
396
            }
397
        }
398
399
        return false;
400
    }
401
402
    /**
403
     * Helper to reply to a chat directly.
404
     *
405
     * @param string $text
406
     * @param array  $data
407
     *
408
     * @return ServerResponse
409
     * @throws TelegramException
410
     */
411
    public function replyToChat(string $text, array $data = []): ServerResponse
412
    {
413
        if ($message = $this->getMessage() ?: $this->getEditedMessage() ?: $this->getChannelPost() ?: $this->getEditedChannelPost()) {
414
            return Request::sendMessage(array_merge([
415
                'chat_id' => $message->getChat()->getId(),
416
                'text'    => $text,
417
            ], $data));
418
        }
419
420
        return Request::emptyResponse();
421
    }
422
423
    /**
424
     * Helper to reply to a user directly.
425
     *
426
     * @param string $text
427
     * @param array  $data
428
     *
429
     * @return ServerResponse
430
     * @throws TelegramException
431
     */
432
    public function replyToUser(string $text, array $data = []): ServerResponse
433
    {
434
        if ($message = $this->getMessage() ?: $this->getEditedMessage()) {
435
            return Request::sendMessage(array_merge([
436
                'chat_id' => $message->getFrom()->getId(),
437
                'text'    => $text,
438
            ], $data));
439
        }
440
441
        return Request::emptyResponse();
442
    }
443
}
444