Completed
Push — master ( cede87...177829 )
by Gusev
02:53
created

BotApi   C

Complexity

Total Complexity 61

Size/Duplication

Total Lines 982
Duplicated Lines 11.51 %

Coupling/Cohesion

Components 1
Dependencies 11

Test Coverage

Coverage 6.79%

Importance

Changes 47
Bugs 11 Features 21
Metric Value
wmc 61
c 47
b 11
f 21
lcom 1
cbo 11
dl 113
loc 982
ccs 15
cts 221
cp 0.0679
rs 5

35 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 2
A setModeObject() 0 6 1
B call() 0 30 5
A executeCurl() 0 9 1
A curlValidate() 0 8 3
A jsonValidate() 0 10 2
A sendMessage() 0 19 2
A sendContact() 19 19 2
A sendChatAction() 0 7 1
A getUserProfilePhotos() 0 8 1
A setWebhook() 0 4 1
A getMe() 0 4 1
A getUpdates() 0 16 3
A sendLocation() 11 17 2
A sendSticker() 10 15 2
A sendVideo() 0 19 2
A sendVoice() 11 17 2
A forwardMessage() 0 9 1
A sendAudio() 0 21 2
A sendPhoto() 11 17 2
A sendDocument() 10 15 2
A getFile() 0 4 1
A downloadFile() 0 12 1
A answerInlineQuery() 0 16 1
A kickChatMember() 0 7 1
A unbanChatMember() 0 7 1
A answerCallbackQuery() 0 8 1
A editMessageText() 17 17 2
A editMessageCaption() 13 13 2
A editMessageReplyMarkup() 11 11 2
A __destruct() 0 4 2
A getUrl() 0 4 1
A getFileUrl() 0 4 1
A trackUpdate() 0 12 3
A track() 0 6 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like BotApi often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use BotApi, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace TelegramBot\Api;
4
5
use TelegramBot\Api\Types\ArrayOfUpdates;
6
use TelegramBot\Api\Types\File;
7
use TelegramBot\Api\Types\Message;
8
use TelegramBot\Api\Types\Update;
9
use TelegramBot\Api\Types\User;
10
use TelegramBot\Api\Types\UserProfilePhotos;
11
12
/**
13
 * Class BotApi
14
 *
15
 * @package TelegramBot\Api
16
 */
17
class BotApi
18
{
19
    /**
20
     * HTTP codes
21
     *
22
     * @var array
23
     */
24
    public static $codes = [
25
        // Informational 1xx
26
        100 => 'Continue',
27
        101 => 'Switching Protocols',
28
        102 => 'Processing',            // RFC2518
29
        // Success 2xx
30
        200 => 'OK',
31
        201 => 'Created',
32
        202 => 'Accepted',
33
        203 => 'Non-Authoritative Information',
34
        204 => 'No Content',
35
        205 => 'Reset Content',
36
        206 => 'Partial Content',
37
        207 => 'Multi-Status',          // RFC4918
38
        208 => 'Already Reported',      // RFC5842
39
        226 => 'IM Used',               // RFC3229
40
        // Redirection 3xx
41
        300 => 'Multiple Choices',
42
        301 => 'Moved Permanently',
43
        302 => 'Found', // 1.1
44
        303 => 'See Other',
45
        304 => 'Not Modified',
46
        305 => 'Use Proxy',
47
        // 306 is deprecated but reserved
48
        307 => 'Temporary Redirect',
49
        308 => 'Permanent Redirect',    // RFC7238
50
        // Client Error 4xx
51
        400 => 'Bad Request',
52
        401 => 'Unauthorized',
53
        402 => 'Payment Required',
54
        403 => 'Forbidden',
55
        404 => 'Not Found',
56
        405 => 'Method Not Allowed',
57
        406 => 'Not Acceptable',
58
        407 => 'Proxy Authentication Required',
59
        408 => 'Request Timeout',
60
        409 => 'Conflict',
61
        410 => 'Gone',
62
        411 => 'Length Required',
63
        412 => 'Precondition Failed',
64
        413 => 'Payload Too Large',
65
        414 => 'URI Too Long',
66
        415 => 'Unsupported Media Type',
67
        416 => 'Range Not Satisfiable',
68
        417 => 'Expectation Failed',
69
        422 => 'Unprocessable Entity',                                        // RFC4918
70
        423 => 'Locked',                                                      // RFC4918
71
        424 => 'Failed Dependency',                                           // RFC4918
72
        425 => 'Reserved for WebDAV advanced collections expired proposal',   // RFC2817
73
        426 => 'Upgrade Required',                                            // RFC2817
74
        428 => 'Precondition Required',                                       // RFC6585
75
        429 => 'Too Many Requests',                                           // RFC6585
76
        431 => 'Request Header Fields Too Large',                             // RFC6585
77
        // Server Error 5xx
78
        500 => 'Internal Server Error',
79
        501 => 'Not Implemented',
80
        502 => 'Bad Gateway',
81
        503 => 'Service Unavailable',
82
        504 => 'Gateway Timeout',
83
        505 => 'HTTP Version Not Supported',
84
        506 => 'Variant Also Negotiates (Experimental)',                      // RFC2295
85
        507 => 'Insufficient Storage',                                        // RFC4918
86
        508 => 'Loop Detected',                                               // RFC5842
87
        510 => 'Not Extended',                                                // RFC2774
88
        511 => 'Network Authentication Required',                             // RFC6585
89
    ];
90
91
92
    /**
93
     * Default http status code
94
     */
95
    const DEFAULT_STATUS_CODE = 200;
96
97
    /**
98
     * Not Modified http status code
99
     */
100
    const NOT_MODIFIED_STATUS_CODE = 304;
101
102
    /**
103
     * Limits for tracked ids
104
     */
105
    const MAX_TRACKED_EVENTS = 200;
106
107
    /**
108
     * Url prefixes
109
     */
110
    const URL_PREFIX = 'https://api.telegram.org/bot';
111
112
    /**
113
     * Url prefix for files
114
     */
115
    const FILE_URL_PREFIX = 'https://api.telegram.org/file/bot';
116
117
    /**
118
     * CURL object
119
     *
120
     * @var
121
     */
122
    protected $curl;
123
124
    /**
125
     * Bot token
126
     *
127
     * @var string
128
     */
129
    protected $token;
130
131
    /**
132
     * Botan tracker
133
     *
134
     * @var \TelegramBot\Api\Botan
135
     */
136
    protected $tracker;
137
138
    /**
139
     * list of event ids
140
     *
141
     * @var array
142
     */
143
    protected $trackedEvents = [];
144
145
    /**
146
     * Check whether return associative array
147
     *
148
     * @var bool
149
     */
150
    protected $returnArray = true;
151
152
153
    /**
154
     * Constructor
155
     *
156
     * @param string $token Telegram Bot API token
157
     * @param string|null $trackerToken Yandex AppMetrica application api_key
158
     */
159 9
    public function __construct($token, $trackerToken = null)
160
    {
161 9
        $this->curl = curl_init();
162 9
        $this->token = $token;
163
164 9
        if ($trackerToken) {
165
            $this->tracker = new Botan($trackerToken);
166
        }
167 9
    }
168
169
    /**
170
     * Set return array
171
     *
172
     * @param bool $mode
173
     *
174
     * @return $this
175
     */
176
    public function setModeObject($mode = true)
177
    {
178
        $this->returnArray = !$mode;
179
180
        return $this;
181
    }
182
183
184
    /**
185
     * Call method
186
     *
187
     * @param string $method
188
     * @param array|null $data
189
     *
190
     * @return mixed
191
     * @throws \TelegramBot\Api\Exception
192
     * @throws \TelegramBot\Api\HttpException
193
     * @throws \TelegramBot\Api\InvalidJsonException
194
     */
195
    public function call($method, array $data = null)
196
    {
197
        $options = [
198
            CURLOPT_URL => $this->getUrl() . '/' . $method,
199
            CURLOPT_RETURNTRANSFER => true,
200
            CURLOPT_POST => null,
201
            CURLOPT_POSTFIELDS => null
202
        ];
203
204
        if ($data) {
205
            $options[CURLOPT_POST] = true;
206
            $options[CURLOPT_POSTFIELDS] = $data;
207
        }
208
209
        $response = self::jsonValidate($this->executeCurl($options), $this->returnArray);
210
211
        if ($this->returnArray) {
212
            if (!isset($response['ok'])) {
213
                throw new Exception($response['description'], $response['error_code']);
214
            }
215
216
            return $response['result'];
217
        }
218
219
        if (!$response->ok) {
220
            throw new Exception($response->description, $response->error_code);
221
        }
222
223
        return $response->result;
224
    }
225
226
    /**
227
     * curl_exec wrapper for response validation
228
     *
229
     * @param array $options
230
     *
231
     * @return string
232
     *
233
     * @throws \TelegramBot\Api\HttpException
234
     */
235
    protected function executeCurl(array $options)
236
    {
237
        curl_setopt_array($this->curl, $options);
238
239
        $result = curl_exec($this->curl);
240
        self::curlValidate($this->curl);
241
242
        return $result;
243
    }
244
245
    /**
246
     * Response validation
247
     *
248
     * @param resource $curl
249
     *
250
     * @throws \TelegramBot\Api\HttpException
251
     */
252
    public static function curlValidate($curl)
253
    {
254
        if (($httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE))
255
            && !in_array($httpCode, [self::DEFAULT_STATUS_CODE, self::NOT_MODIFIED_STATUS_CODE])
256
        ) {
257
            throw new HttpException(self::$codes[$httpCode], $httpCode);
258
        }
259
    }
260
261
    /**
262
     * JSON validation
263
     *
264
     * @param string $jsonString
265
     * @param boolean $asArray
266
     *
267
     * @return object|array
268
     * @throws \TelegramBot\Api\InvalidJsonException
269
     */
270
    public static function jsonValidate($jsonString, $asArray)
271
    {
272
        $json = json_decode($jsonString, $asArray);
273
274
        if (json_last_error() != JSON_ERROR_NONE) {
275
            throw new InvalidJsonException(json_last_error_msg(), json_last_error());
276
        }
277
278
        return $json;
279
    }
280
281
    /**
282
     * Use this method to send text messages. On success, the sent \TelegramBot\Api\Types\Message is returned.
283
     *
284
     * @param int|string $chatId
285
     * @param string $text
286
     * @param string|null $parseMode
287
     * @param bool $disablePreview
288
     * @param int|null $replyToMessageId
289
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
290
     * @param bool $disableNotification
291
     *
292
     * @return \TelegramBot\Api\Types\Message
293
     * @throws \TelegramBot\Api\InvalidArgumentException
294
     * @throws \TelegramBot\Api\Exception
295
     */
296
    public function sendMessage(
297
        $chatId,
298
        $text,
299
        $parseMode = null,
300
        $disablePreview = false,
301
        $replyToMessageId = null,
302
        $replyMarkup = null,
303
        $disableNotification = false
304
    ) {
305
        return Message::fromResponse($this->call('sendMessage', [
306
            'chat_id' => $chatId,
307
            'text' => $text,
308
            'parse_mode' => $parseMode,
309
            'disable_web_page_preview' => $disablePreview,
310
            'reply_to_message_id' => (int) $replyToMessageId,
311
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
312
            'disable_notification' => (bool) $disableNotification,
313
        ]));
314
    }
315
316
    /**
317
     * Use this method to send phone contacts
318
     *
319
     * @param int $chatId
320
     * @param string $phoneNumber
321
     * @param string $firstName
322
     * @param string $lastName
323
     * @param int|null $replyToMessageId
324
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
325
     * @param bool $disableNotification
326
     *
327
     * @return \TelegramBot\Api\Types\Message
328
     * @throws \TelegramBot\Api\Exception
329
     */
330 View Code Duplication
    public function sendContact(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
331
        $chatId,
332
        $phoneNumber,
333
        $firstName,
334
        $lastName = null,
335
        $replyToMessageId = null,
336
        $replyMarkup = null,
337
        $disableNotification = false
338
    ) {
339
        return Message::fromResponse($this->call('sendContact', [
340
            'chat_id' => $chatId,
341
            'phone_number' => $phoneNumber,
342
            'first_name' => $firstName,
343
            'last_name' => $lastName,
344
            'reply_to_message_id' => $replyToMessageId,
345
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
346
            'disable_notification' => (bool)$disableNotification,
347
        ]));
348
    }
349
350
    /**
351
     * Use this method when you need to tell the user that something is happening on the bot's side.
352
     * The status is set for 5 seconds or less (when a message arrives from your bot,
353
     * Telegram clients clear its typing status).
354
     *
355
     * We only recommend using this method when a response from the bot will take a noticeable amount of time to arrive.
356
     *
357
     * Type of action to broadcast. Choose one, depending on what the user is about to receive:
358
     * `typing` for text messages, `upload_photo` for photos, `record_video` or `upload_video` for videos,
359
     * `record_audio` or upload_audio for audio files, `upload_document` for general files,
360
     * `find_location` for location data.
361
     *
362
     * @param int $chatId
363
     * @param string $action
364
     *
365
     * @return bool
366
     * @throws \TelegramBot\Api\Exception
367
     */
368
    public function sendChatAction($chatId, $action)
369
    {
370
        return $this->call('sendChatAction', [
371
            'chat_id' => $chatId,
372
            'action' => $action
373
        ]);
374
    }
375
376
    /**
377
     * Use this method to get a list of profile pictures for a user.
378
     *
379
     * @param int $userId
380
     * @param int $offset
381
     * @param int $limit
382
     *
383
     * @return \TelegramBot\Api\Types\UserProfilePhotos
384
     * @throws \TelegramBot\Api\Exception
385
     */
386
    public function getUserProfilePhotos($userId, $offset = 0, $limit = 100)
387
    {
388
        return UserProfilePhotos::fromResponse($this->call('getUserProfilePhotos', [
389
            'user_id' => (int) $userId,
390
            'offset' => (int) $offset,
391
            'limit' => (int) $limit,
392
        ]));
393
    }
394
395
    /**
396
     * Use this method to specify a url and receive incoming updates via an outgoing webhook.
397
     * Whenever there is an update for the bot, we will send an HTTPS POST request to the specified url,
398
     * containing a JSON-serialized Update.
399
     * In case of an unsuccessful request, we will give up after a reasonable amount of attempts.
400
     *
401
     * @param string $url HTTPS url to send updates to. Use an empty string to remove webhook integration
402
     * @param \CURLFile|string $certificate Upload your public key certificate
403
     *                                      so that the root certificate in use can be checked
404
     *
405
     * @return string
406
     *
407
     * @throws \TelegramBot\Api\Exception
408
     */
409
    public function setWebhook($url = '', $certificate = null)
410
    {
411
        return $this->call('setWebhook', ['url' => $url, 'certificate' => $certificate]);
412
    }
413
414
    /**
415
     * A simple method for testing your bot's auth token.Requires no parameters.
416
     * Returns basic information about the bot in form of a User object.
417
     *
418
     * @return \TelegramBot\Api\Types\User
419
     * @throws \TelegramBot\Api\Exception
420
     * @throws \TelegramBot\Api\InvalidArgumentException
421
     */
422
    public function getMe()
423
    {
424
        return User::fromResponse($this->call('getMe'));
425
    }
426
427
    /**
428
     * Use this method to receive incoming updates using long polling.
429
     * An Array of Update objects is returned.
430
     *
431
     * Notes
432
     * 1. This method will not work if an outgoing webhook is set up.
433
     * 2. In order to avoid getting duplicate updates, recalculate offset after each server response.
434
     *
435
     * @param int $offset
436
     * @param int $limit
437
     * @param int $timeout
438
     *
439
     * @return Update[]
440
     * @throws \TelegramBot\Api\Exception
441
     * @throws \TelegramBot\Api\InvalidArgumentException
442
     */
443 2
    public function getUpdates($offset = 0, $limit = 100, $timeout = 0)
444
    {
445 2
        $updates = ArrayOfUpdates::fromResponse($this->call('getUpdates', [
446 2
            'offset' => $offset,
447 2
            'limit' => $limit,
448
            'timeout' => $timeout
449 2
        ]));
450
451 2
        if ($this->tracker instanceof Botan) {
452
            foreach ($updates as $update) {
453
                $this->trackUpdate($update);
454
            }
455
        }
456
457 2
        return $updates;
458
    }
459
460
    /**
461
     * Use this method to send point on the map. On success, the sent Message is returned.
462
     *
463
     * @param int $chatId
464
     * @param float $latitude
465
     * @param float $longitude
466
     * @param int|null $replyToMessageId
467
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
468
     * @param bool $disableNotification
469
     *
470
     * @return \TelegramBot\Api\Types\Message
471
     * @throws \TelegramBot\Api\Exception
472
     */
473 View Code Duplication
    public function sendLocation(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
474
        $chatId,
475
        $latitude,
476
        $longitude,
477
        $replyToMessageId = null,
478
        $replyMarkup = null,
479
        $disableNotification = false
480
    ) {
481
        return Message::fromResponse($this->call('sendLocation', [
482
            'chat_id' => $chatId,
483
            'latitude' => $latitude,
484
            'longitude' => $longitude,
485
            'reply_to_message_id' => $replyToMessageId,
486
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
487
            'disable_notification' => (bool) $disableNotification
488
        ]));
489
    }
490
491
    /**
492
     * Use this method to send .webp stickers. On success, the sent Message is returned.
493
     *
494
     * @param int $chatId
495
     * @param \CURLFile|string $sticker
496
     * @param int|null $replyToMessageId
497
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
498
     * @param bool $disableNotification
499
     *
500
     * @return \TelegramBot\Api\Types\Message
501
     * @throws \TelegramBot\Api\InvalidArgumentException
502
     * @throws \TelegramBot\Api\Exception
503
     */
504 View Code Duplication
    public function sendSticker(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
505
        $chatId,
506
        $sticker,
507
        $replyToMessageId = null,
508
        $replyMarkup = null,
509
        $disableNotification = false
510
    ) {
511
        return Message::fromResponse($this->call('sendSticker', [
512
            'chat_id' => $chatId,
513
            'sticker' => $sticker,
514
            'reply_to_message_id' => $replyToMessageId,
515
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
516
            'disable_notification' => (bool) $disableNotification
517
        ]));
518
    }
519
520
    /**
521
     * Use this method to send video files,
522
     * Telegram clients support mp4 videos (other formats may be sent as Document).
523
     * On success, the sent Message is returned.
524
     *
525
     * @param int $chatId
526
     * @param \CURLFile|string $video
527
     * @param int|null $duration
528
     * @param string|null $caption
529
     * @param int|null $replyToMessageId
530
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
531
     * @param bool $disableNotification
532
     *
533
     * @return \TelegramBot\Api\Types\Message
534
     * @throws \TelegramBot\Api\InvalidArgumentException
535
     * @throws \TelegramBot\Api\Exception
536
     */
537
    public function sendVideo(
538
        $chatId,
539
        $video,
540
        $duration = null,
541
        $caption = null,
542
        $replyToMessageId = null,
543
        $replyMarkup = null,
544
        $disableNotification = false
545
    ) {
546
        return Message::fromResponse($this->call('sendVideo', [
547
            'chat_id' => $chatId,
548
            'video' => $video,
549
            'duration' => $duration,
550
            'caption' => $caption,
551
            'reply_to_message_id' => $replyToMessageId,
552
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
553
            'disable_notification' => (bool) $disableNotification
554
        ]));
555
    }
556
557
    /**
558
     * Use this method to send audio files,
559
     * if you want Telegram clients to display the file as a playable voice message.
560
     * For this to work, your audio must be in an .ogg file encoded with OPUS
561
     * (other formats may be sent as Audio or Document).
562
     * On success, the sent Message is returned.
563
     * Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
564
     *
565
     * @param int $chatId
566
     * @param \CURLFile|string $voice
567
     * @param int|null $duration
568
     * @param int|null $replyToMessageId
569
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
570
     * @param bool $disableNotification
571
     *
572
     * @return \TelegramBot\Api\Types\Message
573
     * @throws \TelegramBot\Api\InvalidArgumentException
574
     * @throws \TelegramBot\Api\Exception
575
     */
576 View Code Duplication
    public function sendVoice(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
577
        $chatId,
578
        $voice,
579
        $duration = null,
580
        $replyToMessageId = null,
581
        $replyMarkup = null,
582
        $disableNotification = false
583
    ) {
584
        return Message::fromResponse($this->call('sendVoice', [
585
            'chat_id' => $chatId,
586
            'voice' => $voice,
587
            'duration' => $duration,
588
            'reply_to_message_id' => $replyToMessageId,
589
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
590
            'disable_notification' => (bool) $disableNotification
591
        ]));
592
    }
593
594
    /**
595
     * Use this method to forward messages of any kind. On success, the sent Message is returned.
596
     *
597
     * @param int $chatId
598
     * @param int $fromChatId
599
     * @param int $messageId
600
     * @param bool $disableNotification
601
     *
602
     * @return \TelegramBot\Api\Types\Message
603
     * @throws \TelegramBot\Api\InvalidArgumentException
604
     * @throws \TelegramBot\Api\Exception
605
     */
606
    public function forwardMessage($chatId, $fromChatId, $messageId, $disableNotification = false)
607
    {
608
        return Message::fromResponse($this->call('forwardMessage', [
609
            'chat_id' => $chatId,
610
            'from_chat_id' => $fromChatId,
611
            'message_id' => (int) $messageId,
612
            'disable_notification' => (bool) $disableNotification
613
        ]));
614
    }
615
616
    /**
617
     * Use this method to send audio files,
618
     * if you want Telegram clients to display them in the music player.
619
     * Your audio must be in the .mp3 format.
620
     * On success, the sent Message is returned.
621
     * Bots can currently send audio files of up to 50 MB in size, this limit may be changed in the future.
622
     *
623
     * For backward compatibility, when the fields title and performer are both empty
624
     * and the mime-type of the file to be sent is not audio/mpeg, the file will be sent as a playable voice message.
625
     * For this to work, the audio must be in an .ogg file encoded with OPUS.
626
     * This behavior will be phased out in the future. For sending voice messages, use the sendVoice method instead.
627
     *
628
     * @deprecated since 20th February. Removed backward compatibility from the method sendAudio.
629
     * Voice messages now must be sent using the method sendVoice.
630
     * There is no more need to specify a non-empty title or performer while sending the audio by file_id.
631
     *
632
     * @param int $chatId
633
     * @param \CURLFile|string $audio
634
     * @param int|null $duration
635
     * @param string|null $performer
636
     * @param string|null $title
637
     * @param int|null $replyToMessageId
638
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
639
     * @param bool $disableNotification
640
     *
641
     * @return \TelegramBot\Api\Types\Message
642
     * @throws \TelegramBot\Api\InvalidArgumentException
643
     * @throws \TelegramBot\Api\Exception
644
     */
645
    public function sendAudio(
646
        $chatId,
647
        $audio,
648
        $duration = null,
649
        $performer = null,
650
        $title = null,
651
        $replyToMessageId = null,
652
        $replyMarkup = null,
653
        $disableNotification = false
654
    ) {
655
        return Message::fromResponse($this->call('sendAudio', [
656
            'chat_id' => $chatId,
657
            'audio' => $audio,
658
            'duration' => $duration,
659
            'performer' => $performer,
660
            'title' => $title,
661
            'reply_to_message_id' => $replyToMessageId,
662
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
663
            'disable_notification' => (bool) $disableNotification
664
        ]));
665
    }
666
667
    /**
668
     * Use this method to send photos. On success, the sent Message is returned.
669
     *
670
     * @param int $chatId
671
     * @param \CURLFile|string $photo
672
     * @param string|null $caption
673
     * @param int|null $replyToMessageId
674
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
675
     * @param bool $disableNotification
676
     *
677
     * @return \TelegramBot\Api\Types\Message
678
     * @throws \TelegramBot\Api\InvalidArgumentException
679
     * @throws \TelegramBot\Api\Exception
680
     */
681 View Code Duplication
    public function sendPhoto(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
682
        $chatId,
683
        $photo,
684
        $caption = null,
685
        $replyToMessageId = null,
686
        $replyMarkup = null,
687
        $disableNotification = false
688
    ) {
689
        return Message::fromResponse($this->call('sendPhoto', [
690
            'chat_id' => $chatId,
691
            'photo' => $photo,
692
            'caption' => $caption,
693
            'reply_to_message_id' => $replyToMessageId,
694
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
695
            'disable_notification' => (bool) $disableNotification
696
        ]));
697
    }
698
699
    /**
700
     * Use this method to send general files. On success, the sent Message is returned.
701
     * Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
702
     *
703
     * @param int $chatId
704
     * @param \CURLFile|string $document
705
     * @param int|null $replyToMessageId
706
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
707
     * @param bool $disableNotification
708
     *
709
     * @return \TelegramBot\Api\Types\Message
710
     * @throws \TelegramBot\Api\InvalidArgumentException
711
     * @throws \TelegramBot\Api\Exception
712
     */
713 View Code Duplication
    public function sendDocument(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
714
        $chatId,
715
        $document,
716
        $replyToMessageId = null,
717
        $replyMarkup = null,
718
        $disableNotification = false
719
    ) {
720
        return Message::fromResponse($this->call('sendDocument', [
721
            'chat_id' => $chatId,
722
            'document' => $document,
723
            'reply_to_message_id' => $replyToMessageId,
724
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
725
            'disable_notification' => (bool) $disableNotification
726
        ]));
727
    }
728
729
    /**
730
     * Use this method to get basic info about a file and prepare it for downloading.
731
     * For the moment, bots can download files of up to 20MB in size.
732
     * On success, a File object is returned.
733
     * The file can then be downloaded via the link https://api.telegram.org/file/bot<token>/<file_path>,
734
     * where <file_path> is taken from the response.
735
     * It is guaranteed that the link will be valid for at least 1 hour.
736
     * When the link expires, a new one can be requested by calling getFile again.
737
     *
738
     * @param $fileId
739
     *
740
     * @return \TelegramBot\Api\Types\File
741
     * @throws \TelegramBot\Api\InvalidArgumentException
742
     * @throws \TelegramBot\Api\Exception
743
     */
744
    public function getFile($fileId)
745
    {
746
        return File::fromResponse($this->call('getFile', ['file_id' => $fileId]));
747
    }
748
749
    /**
750
     * Get file contents via cURL
751
     *
752
     * @param $fileId
753
     *
754
     * @return string
755
     *
756
     * @throws \TelegramBot\Api\HttpException
757
     */
758
    public function downloadFile($fileId)
759
    {
760
        $file = $this->getFile($fileId);
761
        $options = [
762
            CURLOPT_HEADER => 0,
763
            CURLOPT_HTTPGET => 1,
764
            CURLOPT_RETURNTRANSFER => 1,
765
            CURLOPT_URL => $this->getFileUrl() . '/' . $file->getFilePath()
766
        ];
767
768
        return $this->executeCurl($options);
769
    }
770
771
    /**
772
     * Use this method to send answers to an inline query. On success, True is returned.
773
     * No more than 50 results per query are allowed.
774
     *
775
     * @param string $inlineQueryId
776
     * @param \TelegramBot\Api\Types\Inline\AbstractInlineQueryResult[] $results
777
     * @param int $cacheTime
778
     * @param bool $isPersonal
779
     * @param string $nextOffset
780
     *
781
     * @return mixed
782
     * @throws Exception
783
     */
784
    public function answerInlineQuery($inlineQueryId, $results, $cacheTime = 300, $isPersonal = false, $nextOffset = '')
785
    {
786
        $results = array_map(function ($item) {
787
            /* @var \TelegramBot\Api\Types\Inline\AbstractInlineQueryResult $item */
788
789
            return json_decode($item->toJson(), true);
790
        }, $results);
791
792
        return $this->call('answerInlineQuery', [
793
            'inline_query_id' => $inlineQueryId,
794
            'results' => json_encode($results),
795
            'cache_time' => $cacheTime,
796
            'is_personal' => $isPersonal,
797
            'next_offset' => $nextOffset,
798
        ]);
799
    }
800
801
    /**
802
     * Use this method to kick a user from a group or a supergroup.
803
     * In the case of supergroups, the user will not be able to return to the group
804
     * on their own using invite links, etc., unless unbanned first.
805
     * The bot must be an administrator in the group for this to work. Returns True on success.
806
     *
807
     * @param int|string $chatId Unique identifier for the target group
808
     * or username of the target supergroup (in the format @supergroupusername)
809
     * @param int $userId Unique identifier of the target user
810
     *
811
     * @return bool
812
     */
813
    public function kickChatMember($chatId, $userId)
814
    {
815
        return $this->call('kickChatMember', [
816
            'chat_id' => $chatId,
817
            'user_id' => $userId,
818
        ]);
819
    }
820
821
    /**
822
     * Use this method to unban a previously kicked user in a supergroup.
823
     * The user will not return to the group automatically, but will be able to join via link, etc.
824
     * The bot must be an administrator in the group for this to work. Returns True on success.
825
     *
826
     * @param int|string $chatId Unique identifier for the target group
827
     * or username of the target supergroup (in the format @supergroupusername)
828
     * @param int $userId Unique identifier of the target user
829
     *
830
     * @return bool
831
     */
832
    public function unbanChatMember($chatId, $userId)
833
    {
834
        return $this->call('unbanChatMember', [
835
            'chat_id' => $chatId,
836
            'user_id' => $userId,
837
        ]);
838
    }
839
840
    /**
841
     * Use this method to send answers to callback queries sent from inline keyboards.
842
     * The answer will be displayed to the user as a notification at the top of the chat screen or as an alert.
843
     *
844
     * @param $callbackQueryId
845
     * @param null $text
846
     * @param bool $showAlert
847
     *
848
     * @return bool
849
     */
850
    public function answerCallbackQuery($callbackQueryId, $text = null, $showAlert = false)
851
    {
852
        return $this->call('answerCallbackQuery', [
853
            'callback_query_id' => $callbackQueryId,
854
            'text' => $text,
855
            'show_alert' => (bool)$showAlert,
856
        ]);
857
    }
858
859
860
    /**
861
     * Use this method to edit text messages sent by the bot or via the bot
862
     *
863
     * @param int|string $chatId
864
     * @param int $messageId
865
     * @param string $text
866
     * @param string|null $parseMode
867
     * @param bool $disablePreview
868
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
869
     *
870
     * @return \TelegramBot\Api\Types\Message
871
     * @throws \TelegramBot\Api\InvalidArgumentException
872
     * @throws \TelegramBot\Api\Exception
873
     */
874 View Code Duplication
    public function editMessageText(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
875
        $chatId,
876
        $messageId,
877
        $text,
878
        $parseMode = null,
879
        $disablePreview = false,
880
        $replyMarkup = null
881
    ) {
882
        return Message::fromResponse($this->call('editMessageText', [
883
            'chat_id' => $chatId,
884
            'message_id' => $messageId,
885
            'text' => $text,
886
            'parse_mode' => $parseMode,
887
            'disable_web_page_preview' => $disablePreview,
888
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
889
        ]));
890
    }
891
892
    /**
893
     * Use this method to edit text messages sent by the bot or via the bot
894
     *
895
     * @param int|string $chatId
896
     * @param int $messageId
897
     * @param string|null $caption
898
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
899
     *
900
     * @return \TelegramBot\Api\Types\Message
901
     * @throws \TelegramBot\Api\InvalidArgumentException
902
     * @throws \TelegramBot\Api\Exception
903
     */
904 View Code Duplication
    public function editMessageCaption(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
905
        $chatId,
906
        $messageId,
907
        $caption = null,
908
        $replyMarkup = null
909
    ) {
910
        return Message::fromResponse($this->call('editMessageText', [
911
            'chat_id' => $chatId,
912
            'message_id' => $messageId,
913
            'caption' => $caption,
914
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
915
        ]));
916
    }
917
918
    /**
919
     * Use this method to edit only the reply markup of messages sent by the bot or via the bot
920
     *
921
     * @param int|string $chatId
922
     * @param int $messageId
923
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
924
     *
925
     * @return \TelegramBot\Api\Types\Message
926
     * @throws \TelegramBot\Api\InvalidArgumentException
927
     * @throws \TelegramBot\Api\Exception
928
     */
929 View Code Duplication
    public function editMessageReplyMarkup(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
930
        $chatId,
931
        $messageId,
932
        $replyMarkup = null
933
    ) {
934
        return Message::fromResponse($this->call('editMessageText', [
935
            'chat_id' => $chatId,
936
            'message_id' => $messageId,
937
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
938
        ]));
939
    }
940
941
    /**
942
     * Close curl
943
     */
944 9
    public function __destruct()
945
    {
946 9
        $this->curl && curl_close($this->curl);
947 9
    }
948
949
    /**
950
     * @return string
951
     */
952
    public function getUrl()
953
    {
954
        return self::URL_PREFIX . $this->token;
955
    }
956
957
    /**
958
     * @return string
959
     */
960
    public function getFileUrl()
961
    {
962
        return self::FILE_URL_PREFIX . $this->token;
963
    }
964
965
    /**
966
     * @param \TelegramBot\Api\Types\Update $update
967
     * @param string $eventName
968
     *
969
     * @throws \TelegramBot\Api\Exception
970
     */
971
    public function trackUpdate(Update $update, $eventName = 'Message')
972
    {
973
        if (!in_array($update->getUpdateId(), $this->trackedEvents)) {
974
            $this->trackedEvents[] = $update->getUpdateId();
975
976
            $this->track($update->getMessage(), $eventName);
977
978
            if (count($this->trackedEvents) > self::MAX_TRACKED_EVENTS) {
979
                $this->trackedEvents = array_slice($this->trackedEvents, round(self::MAX_TRACKED_EVENTS / 4));
980
            }
981
        }
982
    }
983
984
    /**
985
     * Wrapper for tracker
986
     *
987
     * @param \TelegramBot\Api\Types\Message $message
988
     * @param string $eventName
989
     *
990
     * @throws \TelegramBot\Api\Exception
991
     */
992
    public function track(Message $message, $eventName = 'Message')
993
    {
994
        if ($this->tracker instanceof Botan) {
995
            $this->tracker->track($message, $eventName);
996
        }
997
    }
998
}
999