Passed
Push — master ( b1333b...dd9270 )
by
unknown
02:14 queued 12s
created

BotApi   F

Complexity

Total Complexity 111

Size/Duplication

Total Lines 1853
Duplicated Lines 6.96 %

Coupling/Cohesion

Components 1
Dependencies 18

Test Coverage

Coverage 3.51%

Importance

Changes 0
Metric Value
wmc 111
lcom 1
cbo 18
dl 129
loc 1853
ccs 16
cts 456
cp 0.0351
rs 0.8
c 0
b 0
f 0

67 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 2
A setModeObject() 0 6 1
B call() 0 35 8
A executeCurl() 0 12 2
A curlValidate() 0 11 6
A jsonValidate() 0 10 2
A sendMessage() 0 19 2
A sendContact() 0 19 2
A sendChatAction() 0 7 1
A getUserProfilePhotos() 0 8 1
A setWebhook() 0 4 1
A deleteWebhook() 0 4 1
A getMe() 0 4 1
A getUpdates() 0 16 3
A sendLocation() 0 19 2
A editMessageLiveLocation() 0 17 2
A stopMessageLiveLocation() 0 13 2
A sendVenue() 0 23 2
A sendSticker() 15 15 2
A sendVideo() 23 23 2
A sendAnimation() 21 21 2
A sendVoice() 0 19 2
A forwardMessage() 0 9 1
A sendAudio() 23 23 2
A sendPhoto() 0 19 2
A sendDocument() 0 19 2
A getFile() 0 4 1
A downloadFile() 0 12 1
A answerInlineQuery() 0 24 1
A kickChatMember() 0 8 1
A unbanChatMember() 0 7 1
A answerCallbackQuery() 0 8 1
A editMessageText() 0 19 2
A editMessageCaption() 15 15 2
A editMessageMedia() 15 15 2
A editMessageReplyMarkup() 0 13 2
A deleteMessage() 0 7 1
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
A sendInvoice() 0 51 2
A answerShippingQuery() 0 9 1
A answerPreCheckoutQuery() 0 8 1
A restrictChatMember() 0 19 1
A promoteChatMember() 0 25 1
A exportChatInviteLink() 0 6 1
A setChatPhoto() 0 7 1
A deleteChatPhoto() 0 6 1
A setChatTitle() 0 7 1
A setChatDescription() 0 7 1
A pinChatMessage() 0 8 1
A unpinChatMessage() 0 6 1
A getChat() 0 6 1
A getChatMember() 0 7 1
A leaveChat() 0 6 1
A getChatMembersCount() 0 9 1
A getChatAdministrators() 0 11 1
A sendVideoNote() 0 19 2
A sendMediaGroup() 0 13 1
A setProxy() 0 17 3
A sendPoll() 17 17 2
A stopPoll() 0 11 2
A setCurlOption() 0 4 1
A unsetCurlOption() 0 4 1
A resetCurlOptions() 0 4 1

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\ArrayOfChatMemberEntity;
6
use TelegramBot\Api\Types\ArrayOfMessages;
7
use TelegramBot\Api\Types\ArrayOfUpdates;
8
use TelegramBot\Api\Types\Chat;
9
use TelegramBot\Api\Types\ChatMember;
10
use TelegramBot\Api\Types\File;
11
use TelegramBot\Api\Types\Inline\QueryResult\AbstractInlineQueryResult;
12
use TelegramBot\Api\Types\InputMedia\ArrayOfInputMedia;
13
use TelegramBot\Api\Types\InputMedia\InputMedia;
14
use TelegramBot\Api\Types\Message;
15
use TelegramBot\Api\Types\Poll;
16
use TelegramBot\Api\Types\Update;
17
use TelegramBot\Api\Types\User;
18
use TelegramBot\Api\Types\UserProfilePhotos;
19
20
/**
21
 * Class BotApi
22
 *
23
 * @package TelegramBot\Api
24
 */
25
class BotApi
26
{
27
    /**
28
     * HTTP codes
29
     *
30
     * @var array
31
     */
32
    public static $codes = [
33
        // Informational 1xx
34
        100 => 'Continue',
35
        101 => 'Switching Protocols',
36
        102 => 'Processing',            // RFC2518
37
        // Success 2xx
38
        200 => 'OK',
39
        201 => 'Created',
40
        202 => 'Accepted',
41
        203 => 'Non-Authoritative Information',
42
        204 => 'No Content',
43
        205 => 'Reset Content',
44
        206 => 'Partial Content',
45
        207 => 'Multi-Status',          // RFC4918
46
        208 => 'Already Reported',      // RFC5842
47
        226 => 'IM Used',               // RFC3229
48
        // Redirection 3xx
49
        300 => 'Multiple Choices',
50
        301 => 'Moved Permanently',
51
        302 => 'Found', // 1.1
52
        303 => 'See Other',
53
        304 => 'Not Modified',
54
        305 => 'Use Proxy',
55
        // 306 is deprecated but reserved
56
        307 => 'Temporary Redirect',
57
        308 => 'Permanent Redirect',    // RFC7238
58
        // Client Error 4xx
59
        400 => 'Bad Request',
60
        401 => 'Unauthorized',
61
        402 => 'Payment Required',
62
        403 => 'Forbidden',
63
        404 => 'Not Found',
64
        405 => 'Method Not Allowed',
65
        406 => 'Not Acceptable',
66
        407 => 'Proxy Authentication Required',
67
        408 => 'Request Timeout',
68
        409 => 'Conflict',
69
        410 => 'Gone',
70
        411 => 'Length Required',
71
        412 => 'Precondition Failed',
72
        413 => 'Payload Too Large',
73
        414 => 'URI Too Long',
74
        415 => 'Unsupported Media Type',
75
        416 => 'Range Not Satisfiable',
76
        417 => 'Expectation Failed',
77
        422 => 'Unprocessable Entity',                                        // RFC4918
78
        423 => 'Locked',                                                      // RFC4918
79
        424 => 'Failed Dependency',                                           // RFC4918
80
        425 => 'Reserved for WebDAV advanced collections expired proposal',   // RFC2817
81
        426 => 'Upgrade Required',                                            // RFC2817
82
        428 => 'Precondition Required',                                       // RFC6585
83
        429 => 'Too Many Requests',                                           // RFC6585
84
        431 => 'Request Header Fields Too Large',                             // RFC6585
85
        // Server Error 5xx
86
        500 => 'Internal Server Error',
87
        501 => 'Not Implemented',
88
        502 => 'Bad Gateway',
89
        503 => 'Service Unavailable',
90
        504 => 'Gateway Timeout',
91
        505 => 'HTTP Version Not Supported',
92
        506 => 'Variant Also Negotiates (Experimental)',                      // RFC2295
93
        507 => 'Insufficient Storage',                                        // RFC4918
94
        508 => 'Loop Detected',                                               // RFC5842
95
        510 => 'Not Extended',                                                // RFC2774
96
        511 => 'Network Authentication Required',                             // RFC6585
97
    ];
98
99
    private $proxySettings = [];
100
101
    /**
102
     * Default http status code
103
     */
104
    const DEFAULT_STATUS_CODE = 200;
105
106
    /**
107
     * Not Modified http status code
108
     */
109
    const NOT_MODIFIED_STATUS_CODE = 304;
110
111
    /**
112
     * Limits for tracked ids
113
     */
114
    const MAX_TRACKED_EVENTS = 200;
115
116
    /**
117
     * Url prefixes
118
     */
119
    const URL_PREFIX = 'https://api.telegram.org/bot';
120
121
    /**
122
     * Url prefix for files
123
     */
124
    const FILE_URL_PREFIX = 'https://api.telegram.org/file/bot';
125
126
    /**
127
     * CURL object
128
     *
129
     * @var
130
     */
131
    protected $curl;
132
133
    /**
134
     * CURL custom options
135
     *
136
     * @var array
137
     */
138
    protected $customCurlOptions = [];
139
140
    /**
141
     * Bot token
142
     *
143
     * @var string
144
     */
145
    protected $token;
146
147
    /**
148
     * Botan tracker
149
     *
150
     * @var \TelegramBot\Api\Botan
151
     */
152
    protected $tracker;
153
154
    /**
155
     * list of event ids
156
     *
157
     * @var array
158
     */
159
    protected $trackedEvents = [];
160
161
    /**
162
     * Check whether return associative array
163
     *
164
     * @var bool
165
     */
166
    protected $returnArray = true;
167
168
    /**
169
     * Constructor
170
     *
171
     * @param string $token Telegram Bot API token
172
     * @param string|null $trackerToken Yandex AppMetrica application api_key
173
     */
174 9
    public function __construct($token, $trackerToken = null)
175
    {
176 9
        $this->curl = curl_init();
177 9
        $this->token = $token;
178
179 9
        if ($trackerToken) {
180
            $this->tracker = new Botan($trackerToken);
181
        }
182 9
    }
183
184
    /**
185
     * Set return array
186
     *
187
     * @param bool $mode
188
     *
189
     * @return $this
190
     */
191
    public function setModeObject($mode = true)
192
    {
193
        $this->returnArray = !$mode;
194
195
        return $this;
196
    }
197
198
199
    /**
200
     * Call method
201
     *
202
     * @param string $method
203
     * @param array|null $data
204
     *
205
     * @return mixed
206
     * @throws \TelegramBot\Api\Exception
207
     * @throws \TelegramBot\Api\HttpException
208
     * @throws \TelegramBot\Api\InvalidJsonException
209
     */
210
    public function call($method, array $data = null)
211
    {
212
        $options = $this->proxySettings + [
213
            CURLOPT_URL => $this->getUrl().'/'.$method,
214
            CURLOPT_RETURNTRANSFER => true,
215
            CURLOPT_POST => null,
216
            CURLOPT_POSTFIELDS => null,
217
            CURLOPT_TIMEOUT => 5,
218
        ];
219
220
        if ($data) {
221
            $options[CURLOPT_POST] = true;
222
            $options[CURLOPT_POSTFIELDS] = $data;
223
        }
224
225
        if (!empty($this->customCurlOptions) && is_array($this->customCurlOptions)) {
226
            $options = $this->customCurlOptions + $options;
227
        }
228
229
        $response = self::jsonValidate($this->executeCurl($options), $this->returnArray);
230
231
        if ($this->returnArray) {
232
            if (!isset($response['ok']) || !$response['ok']) {
233
                throw new Exception($response['description'], $response['error_code']);
234
            }
235
236
            return $response['result'];
237
        }
238
239
        if (!$response->ok) {
240
            throw new Exception($response->description, $response->error_code);
241
        }
242
243
        return $response->result;
244
    }
245
246
    /**
247
     * curl_exec wrapper for response validation
248
     *
249
     * @param array $options
250
     *
251
     * @return string
252
     *
253
     * @throws \TelegramBot\Api\HttpException
254
     */
255
    protected function executeCurl(array $options)
256
    {
257
        curl_setopt_array($this->curl, $options);
258
259
        $result = curl_exec($this->curl);
260
        self::curlValidate($this->curl, $result);
261
        if ($result === false) {
262
            throw new HttpException(curl_error($this->curl), curl_errno($this->curl));
263
        }
264
265
        return $result;
266
    }
267
268
    /**
269
     * Response validation
270
     *
271
     * @param resource $curl
272
     * @param string $response
273
     * @throws HttpException
274
     */
275
    public static function curlValidate($curl, $response = null)
276
    {
277
        $json = json_decode($response, true)?: [];
278
        if (($httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE))
279
            && !in_array($httpCode, [self::DEFAULT_STATUS_CODE, self::NOT_MODIFIED_STATUS_CODE])
280
        ) {
281
            $errorDescription = array_key_exists('description', $json) ? $json['description'] : self::$codes[$httpCode];
282
            $errorParameters = array_key_exists('parameters', $json) ? $json['parameters'] : [];
283
            throw new HttpException($errorDescription, $httpCode, null, $errorParameters);
284
        }
285
    }
286
287
    /**
288
     * JSON validation
289
     *
290
     * @param string $jsonString
291
     * @param boolean $asArray
292
     *
293
     * @return object|array
294
     * @throws \TelegramBot\Api\InvalidJsonException
295
     */
296
    public static function jsonValidate($jsonString, $asArray)
297
    {
298
        $json = json_decode($jsonString, $asArray);
299
300
        if (json_last_error() != JSON_ERROR_NONE) {
301
            throw new InvalidJsonException(json_last_error_msg(), json_last_error());
302
        }
303
304
        return $json;
305
    }
306
307
    /**
308
     * Use this method to send text messages. On success, the sent \TelegramBot\Api\Types\Message is returned.
309
     *
310
     * @param int|string $chatId
311
     * @param string $text
312
     * @param string|null $parseMode
313
     * @param bool $disablePreview
314
     * @param int|null $replyToMessageId
315
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
316
     *        Types\ReplyKeyboardRemove|null $replyMarkup
317
     * @param bool $disableNotification
318
     *
319
     * @return \TelegramBot\Api\Types\Message
320
     * @throws \TelegramBot\Api\InvalidArgumentException
321
     * @throws \TelegramBot\Api\Exception
322
     */
323
    public function sendMessage(
324
        $chatId,
325
        $text,
326
        $parseMode = null,
327
        $disablePreview = false,
328
        $replyToMessageId = null,
329
        $replyMarkup = null,
330
        $disableNotification = false
331
    ) {
332
        return Message::fromResponse($this->call('sendMessage', [
333
            'chat_id' => $chatId,
334
            'text' => $text,
335
            'parse_mode' => $parseMode,
336
            'disable_web_page_preview' => $disablePreview,
337
            'reply_to_message_id' => (int)$replyToMessageId,
338
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
339
            'disable_notification' => (bool)$disableNotification,
340
        ]));
341
    }
342
343
    /**
344
     * Use this method to send phone contacts
345
     *
346
     * @param int|string $chatId chat_id or @channel_name
347
     * @param string $phoneNumber
348
     * @param string $firstName
349
     * @param string $lastName
350
     * @param int|null $replyToMessageId
351
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
352
     *        Types\ReplyKeyboardRemove|null $replyMarkup
353
     * @param bool $disableNotification
354
     *
355
     * @return \TelegramBot\Api\Types\Message
356
     * @throws \TelegramBot\Api\Exception
357
     */
358
    public function sendContact(
359
        $chatId,
360
        $phoneNumber,
361
        $firstName,
362
        $lastName = null,
363
        $replyToMessageId = null,
364
        $replyMarkup = null,
365
        $disableNotification = false
366
    ) {
367
        return Message::fromResponse($this->call('sendContact', [
368
            'chat_id' => $chatId,
369
            'phone_number' => $phoneNumber,
370
            'first_name' => $firstName,
371
            'last_name' => $lastName,
372
            'reply_to_message_id' => $replyToMessageId,
373
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
374
            'disable_notification' => (bool)$disableNotification,
375
        ]));
376
    }
377
378
    /**
379
     * Use this method when you need to tell the user that something is happening on the bot's side.
380
     * The status is set for 5 seconds or less (when a message arrives from your bot,
381
     * Telegram clients clear its typing status).
382
     *
383
     * We only recommend using this method when a response from the bot will take a noticeable amount of time to arrive.
384
     *
385
     * Type of action to broadcast. Choose one, depending on what the user is about to receive:
386
     * `typing` for text messages, `upload_photo` for photos, `record_video` or `upload_video` for videos,
387
     * `record_audio` or upload_audio for audio files, `upload_document` for general files,
388
     * `find_location` for location data.
389
     *
390
     * @param int $chatId
391
     * @param string $action
392
     *
393
     * @return bool
394
     * @throws \TelegramBot\Api\Exception
395
     */
396
    public function sendChatAction($chatId, $action)
397
    {
398
        return $this->call('sendChatAction', [
399
            'chat_id' => $chatId,
400
            'action' => $action,
401
        ]);
402
    }
403
404
    /**
405
     * Use this method to get a list of profile pictures for a user.
406
     *
407
     * @param int $userId
408
     * @param int $offset
409
     * @param int $limit
410
     *
411
     * @return \TelegramBot\Api\Types\UserProfilePhotos
412
     * @throws \TelegramBot\Api\Exception
413
     */
414
    public function getUserProfilePhotos($userId, $offset = 0, $limit = 100)
415
    {
416
        return UserProfilePhotos::fromResponse($this->call('getUserProfilePhotos', [
417
            'user_id' => (int)$userId,
418
            'offset' => (int)$offset,
419
            'limit' => (int)$limit,
420
        ]));
421
    }
422
423
    /**
424
     * Use this method to specify a url and receive incoming updates via an outgoing webhook.
425
     * Whenever there is an update for the bot, we will send an HTTPS POST request to the specified url,
426
     * containing a JSON-serialized Update.
427
     * In case of an unsuccessful request, we will give up after a reasonable amount of attempts.
428
     *
429
     * @param string $url HTTPS url to send updates to. Use an empty string to remove webhook integration
430
     * @param \CURLFile|string $certificate Upload your public key certificate
431
     *                                      so that the root certificate in use can be checked
432
     *
433
     * @return string
434
     *
435
     * @throws \TelegramBot\Api\Exception
436
     */
437
    public function setWebhook($url = '', $certificate = null)
438
    {
439
        return $this->call('setWebhook', ['url' => $url, 'certificate' => $certificate]);
440
    }
441
442
443
    /**
444
     * Use this method to clear webhook and use getUpdates again!
445
     *
446
     * @return mixed
447
     *
448
     * @throws \TelegramBot\Api\Exception
449
     */
450
    public function deleteWebhook()
451
    {
452
        return $this->call('deleteWebhook');
453
    }
454
455
    /**
456
     * A simple method for testing your bot's auth token.Requires no parameters.
457
     * Returns basic information about the bot in form of a User object.
458
     *
459
     * @return \TelegramBot\Api\Types\User
460
     * @throws \TelegramBot\Api\Exception
461
     * @throws \TelegramBot\Api\InvalidArgumentException
462
     */
463
    public function getMe()
464
    {
465
        return User::fromResponse($this->call('getMe'));
466
    }
467
468
    /**
469
     * Use this method to receive incoming updates using long polling.
470
     * An Array of Update objects is returned.
471
     *
472
     * Notes
473
     * 1. This method will not work if an outgoing webhook is set up.
474
     * 2. In order to avoid getting duplicate updates, recalculate offset after each server response.
475
     *
476
     * @param int $offset
477
     * @param int $limit
478
     * @param int $timeout
479
     *
480
     * @return Update[]
481
     * @throws \TelegramBot\Api\Exception
482
     * @throws \TelegramBot\Api\InvalidArgumentException
483
     */
484 2
    public function getUpdates($offset = 0, $limit = 100, $timeout = 0)
485
    {
486 2
        $updates = ArrayOfUpdates::fromResponse($this->call('getUpdates', [
487 2
            'offset' => $offset,
488 2
            'limit' => $limit,
489 2
            'timeout' => $timeout,
490 2
        ]));
491
492 2
        if ($this->tracker instanceof Botan) {
493
            foreach ($updates as $update) {
494
                $this->trackUpdate($update);
495
            }
496
        }
497
498 2
        return $updates;
499
    }
500
501
    /**
502
     * Use this method to send point on the map. On success, the sent Message is returned.
503
     *
504
     * @param int|string                                                              $chatId
505
     * @param float                                                                   $latitude
506
     * @param float                                                                   $longitude
507
     * @param int|null                                                                $replyToMessageId
508
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
509
     *        Types\ReplyKeyboardRemove|null $replyMarkup
510
     * @param bool                                                                    $disableNotification
511
     *
512
     * @param null|int                                                                $livePeriod
513
     * @return \TelegramBot\Api\Types\Message
514
     */
515
    public function sendLocation(
516
        $chatId,
517
        $latitude,
518
        $longitude,
519
        $replyToMessageId = null,
520
        $replyMarkup = null,
521
        $disableNotification = false,
522
        $livePeriod = null
523
    ) {
524
        return Message::fromResponse($this->call('sendLocation', [
525
            'chat_id'              => $chatId,
526
            'latitude'             => $latitude,
527
            'longitude'            => $longitude,
528
            'live_period'          => $livePeriod,
529
            'reply_to_message_id'  => $replyToMessageId,
530
            'reply_markup'         => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
531
            'disable_notification' => (bool)$disableNotification,
532
        ]));
533
    }
534
535
    /**
536
     * Use this method to edit live location messages sent by the bot or via the bot (for inline bots).
537
     *
538
     * @param int|string                                                              $chatId
539
     * @param int                                                                     $messageId
540
     * @param string                                                                  $inlineMessageId
541
     * @param float                                                                   $latitude
542
     * @param float                                                                   $longitude
543
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
544
     *        Types\ReplyKeyboardRemove|null $replyMarkup
545
     * @return \TelegramBot\Api\Types\Message
546
     */
547
    public function editMessageLiveLocation(
548
        $chatId,
549
        $messageId,
550
        $inlineMessageId,
551
        $latitude,
552
        $longitude,
553
        $replyMarkup = null
554
    ) {
555
        return Message::fromResponse($this->call('sendLocation', [
556
            'chat_id'           => $chatId,
557
            'message_id'        => $messageId,
558
            'inline_message_id' => $inlineMessageId,
559
            'latitude'          => $latitude,
560
            'longitude'         => $longitude,
561
            'reply_markup'      => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
562
        ]));
563
    }
564
565
    /**
566
     * Use this method to stop updating a live location message sent by the bot or via the bot (for inline bots) before
567
     * live_period expires.
568
     *
569
     * @param int|string                                                              $chatId
570
     * @param int                                                                     $messageId
571
     * @param string                                                                  $inlineMessageId
572
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
573
     *        Types\ReplyKeyboardRemove|null $replyMarkup
574
     * @return \TelegramBot\Api\Types\Message
575
     */
576
    public function stopMessageLiveLocation(
577
        $chatId,
578
        $messageId,
579
        $inlineMessageId,
580
        $replyMarkup = null
581
    ) {
582
        return Message::fromResponse($this->call('sendLocation', [
583
            'chat_id'           => $chatId,
584
            'message_id'        => $messageId,
585
            'inline_message_id' => $inlineMessageId,
586
            'reply_markup'      => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
587
        ]));
588
    }
589
590
    /**
591
     * Use this method to send information about a venue. On success, the sent Message is returned.
592
     *
593
     * @param int|string $chatId chat_id or @channel_name
594
     * @param float $latitude
595
     * @param float $longitude
596
     * @param string $title
597
     * @param string $address
598
     * @param string|null $foursquareId
599
     * @param int|null $replyToMessageId
600
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
601
     *        Types\ReplyKeyboardRemove|null $replyMarkup
602
     * @param bool $disableNotification
603
     *
604
     * @return \TelegramBot\Api\Types\Message
605
     * @throws \TelegramBot\Api\Exception
606
     */
607
    public function sendVenue(
608
        $chatId,
609
        $latitude,
610
        $longitude,
611
        $title,
612
        $address,
613
        $foursquareId = null,
614
        $replyToMessageId = null,
615
        $replyMarkup = null,
616
        $disableNotification = false
617
    ) {
618
        return Message::fromResponse($this->call('sendVenue', [
619
            'chat_id' => $chatId,
620
            'latitude' => $latitude,
621
            'longitude' => $longitude,
622
            'title' => $title,
623
            'address' => $address,
624
            'foursquare_id' => $foursquareId,
625
            'reply_to_message_id' => $replyToMessageId,
626
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
627
            'disable_notification' => (bool)$disableNotification,
628
        ]));
629
    }
630
631
    /**
632
     * Use this method to send .webp stickers. On success, the sent Message is returned.
633
     *
634
     * @param int|string $chatId chat_id or @channel_name
635
     * @param \CURLFile|string $sticker
636
     * @param int|null $replyToMessageId
637
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
638
     *        Types\ReplyKeyboardRemove|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 View Code Duplication
    public function sendSticker(
646
        $chatId,
647
        $sticker,
648
        $replyToMessageId = null,
649
        $replyMarkup = null,
650
        $disableNotification = false
651
    ) {
652
        return Message::fromResponse($this->call('sendSticker', [
653
            'chat_id' => $chatId,
654
            'sticker' => $sticker,
655
            'reply_to_message_id' => $replyToMessageId,
656
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
657
            'disable_notification' => (bool)$disableNotification,
658
        ]));
659
    }
660
661
    /**
662
     * Use this method to send video files,
663
     * Telegram clients support mp4 videos (other formats may be sent as Document).
664
     * On success, the sent Message is returned.
665
     *
666
     * @param int|string $chatId chat_id or @channel_name
667
     * @param \CURLFile|string $video
668
     * @param int|null $duration
669
     * @param string|null $caption
670
     * @param int|null $replyToMessageId
671
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
672
     *        Types\ReplyKeyboardRemove|null $replyMarkup
673
     * @param bool $disableNotification
674
     * @param bool $supportsStreaming Pass True, if the uploaded video is suitable for streaming
675
     * @param string|null $parseMode
676
     *
677
     * @return \TelegramBot\Api\Types\Message
678
     * @throws \TelegramBot\Api\InvalidArgumentException
679
     * @throws \TelegramBot\Api\Exception
680
     */
681 View Code Duplication
    public function sendVideo(
682
        $chatId,
683
        $video,
684
        $duration = null,
685
        $caption = null,
686
        $replyToMessageId = null,
687
        $replyMarkup = null,
688
        $disableNotification = false,
689
        $supportsStreaming = false,
690
        $parseMode = null
691
    ) {
692
        return Message::fromResponse($this->call('sendVideo', [
693
            'chat_id' => $chatId,
694
            'video' => $video,
695
            'duration' => $duration,
696
            'caption' => $caption,
697
            'reply_to_message_id' => $replyToMessageId,
698
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
699
            'disable_notification' => (bool)$disableNotification,
700
            'supports_streaming' => (bool)$supportsStreaming,
701
            'parse_mode' => $parseMode
702
        ]));
703
    }
704
705
    /**
706
     * Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound),
707
     * On success, the sent Message is returned.
708
     * Bots can currently send animation files of up to 50 MB in size, this limit may be changed in the future.
709
     *
710
     * @param int|string $chatId chat_id or @channel_name
711
     * @param \CURLFile|string $animation
712
     * @param int|null $duration
713
     * @param string|null $caption
714
     * @param int|null $replyToMessageId
715
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
716
     *        Types\ReplyKeyboardRemove|null $replyMarkup
717
     * @param bool $disableNotification
718
     * @param string|null $parseMode
719
     *
720
     * @return \TelegramBot\Api\Types\Message
721
     * @throws \TelegramBot\Api\InvalidArgumentException
722
     * @throws \TelegramBot\Api\Exception
723
     */
724 View Code Duplication
    public function sendAnimation(
725
        $chatId,
726
        $animation,
727
        $duration = null,
728
        $caption = null,
729
        $replyToMessageId = null,
730
        $replyMarkup = null,
731
        $disableNotification = false,
732
        $parseMode = null
733
    ) {
734
        return Message::fromResponse($this->call('sendAnimation', [
735
            'chat_id' => $chatId,
736
            'animation' => $animation,
737
            'duration' => $duration,
738
            'caption' => $caption,
739
            'reply_to_message_id' => $replyToMessageId,
740
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
741
            'disable_notification' => (bool)$disableNotification,
742
            'parse_mode' => $parseMode
743
        ]));
744
    }
745
746
    /**
747
     * Use this method to send audio files,
748
     * if you want Telegram clients to display the file as a playable voice message.
749
     * For this to work, your audio must be in an .ogg file encoded with OPUS
750
     * (other formats may be sent as Audio or Document).
751
     * On success, the sent Message is returned.
752
     * Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
753
     *
754
     * @param int|string $chatId chat_id or @channel_name
755
     * @param \CURLFile|string $voice
756
     * @param int|null $duration
757
     * @param int|null $replyToMessageId
758
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
759
     *        Types\ReplyKeyboardRemove|null $replyMarkup
760
     * @param bool $disableNotification
761
     * @param string|null $parseMode
762
     *
763
     * @return \TelegramBot\Api\Types\Message
764
     * @throws \TelegramBot\Api\InvalidArgumentException
765
     * @throws \TelegramBot\Api\Exception
766
     */
767
    public function sendVoice(
768
        $chatId,
769
        $voice,
770
        $duration = null,
771
        $replyToMessageId = null,
772
        $replyMarkup = null,
773
        $disableNotification = false,
774
        $parseMode = null
775
    ) {
776
        return Message::fromResponse($this->call('sendVoice', [
777
            'chat_id' => $chatId,
778
            'voice' => $voice,
779
            'duration' => $duration,
780
            'reply_to_message_id' => $replyToMessageId,
781
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
782
            'disable_notification' => (bool)$disableNotification,
783
            'parse_mode' => $parseMode
784
        ]));
785
    }
786
787
    /**
788
     * Use this method to forward messages of any kind. On success, the sent Message is returned.
789
     *
790
     * @param int|string $chatId chat_id or @channel_name
791
     * @param int $fromChatId
792
     * @param int $messageId
793
     * @param bool $disableNotification
794
     *
795
     * @return \TelegramBot\Api\Types\Message
796
     * @throws \TelegramBot\Api\InvalidArgumentException
797
     * @throws \TelegramBot\Api\Exception
798
     */
799
    public function forwardMessage($chatId, $fromChatId, $messageId, $disableNotification = false)
800
    {
801
        return Message::fromResponse($this->call('forwardMessage', [
802
            'chat_id' => $chatId,
803
            'from_chat_id' => $fromChatId,
804
            'message_id' => (int)$messageId,
805
            'disable_notification' => (bool)$disableNotification,
806
        ]));
807
    }
808
809
    /**
810
     * Use this method to send audio files,
811
     * if you want Telegram clients to display them in the music player.
812
     * Your audio must be in the .mp3 format.
813
     * On success, the sent Message is returned.
814
     * Bots can currently send audio files of up to 50 MB in size, this limit may be changed in the future.
815
     *
816
     * For backward compatibility, when the fields title and performer are both empty
817
     * and the mime-type of the file to be sent is not audio/mpeg, the file will be sent as a playable voice message.
818
     * For this to work, the audio must be in an .ogg file encoded with OPUS.
819
     * This behavior will be phased out in the future. For sending voice messages, use the sendVoice method instead.
820
     *
821
     * @deprecated since 20th February. Removed backward compatibility from the method sendAudio.
822
     * Voice messages now must be sent using the method sendVoice.
823
     * There is no more need to specify a non-empty title or performer while sending the audio by file_id.
824
     *
825
     * @param int|string $chatId chat_id or @channel_name
826
     * @param \CURLFile|string $audio
827
     * @param int|null $duration
828
     * @param string|null $performer
829
     * @param string|null $title
830
     * @param int|null $replyToMessageId
831
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
832
     *        Types\ReplyKeyboardRemove|null $replyMarkup
833
     * @param bool $disableNotification
834
     * @param string|null $parseMode
835
     *
836
     * @return \TelegramBot\Api\Types\Message
837
     * @throws \TelegramBot\Api\InvalidArgumentException
838
     * @throws \TelegramBot\Api\Exception
839
     */
840 View Code Duplication
    public function sendAudio(
841
        $chatId,
842
        $audio,
843
        $duration = null,
844
        $performer = null,
845
        $title = null,
846
        $replyToMessageId = null,
847
        $replyMarkup = null,
848
        $disableNotification = false,
849
        $parseMode = null
850
    ) {
851
        return Message::fromResponse($this->call('sendAudio', [
852
            'chat_id' => $chatId,
853
            'audio' => $audio,
854
            'duration' => $duration,
855
            'performer' => $performer,
856
            'title' => $title,
857
            'reply_to_message_id' => $replyToMessageId,
858
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
859
            'disable_notification' => (bool)$disableNotification,
860
            'parse_mode' => $parseMode
861
        ]));
862
    }
863
864
    /**
865
     * Use this method to send photos. On success, the sent Message is returned.
866
     *
867
     * @param int|string $chatId chat_id or @channel_name
868
     * @param \CURLFile|string $photo
869
     * @param string|null $caption
870
     * @param int|null $replyToMessageId
871
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
872
     *        Types\ReplyKeyboardRemove|null $replyMarkup
873
     * @param bool $disableNotification
874
     * @param string|null $parseMode
875
     *
876
     * @return \TelegramBot\Api\Types\Message
877
     * @throws \TelegramBot\Api\InvalidArgumentException
878
     * @throws \TelegramBot\Api\Exception
879
     */
880
    public function sendPhoto(
881
        $chatId,
882
        $photo,
883
        $caption = null,
884
        $replyToMessageId = null,
885
        $replyMarkup = null,
886
        $disableNotification = false,
887
        $parseMode = null
888
    ) {
889
        return Message::fromResponse($this->call('sendPhoto', [
890
            'chat_id' => $chatId,
891
            'photo' => $photo,
892
            'caption' => $caption,
893
            'reply_to_message_id' => $replyToMessageId,
894
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
895
            'disable_notification' => (bool)$disableNotification,
896
            'parse_mode' => $parseMode
897
        ]));
898
    }
899
900
    /**
901
     * Use this method to send general files. On success, the sent Message is returned.
902
     * Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
903
     *
904
     * @param int|string $chatId chat_id or @channel_name
905
     * @param \CURLFile|string $document
906
     * @param string|null $caption
907
     * @param int|null $replyToMessageId
908
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
909
     *        Types\ReplyKeyboardRemove|null $replyMarkup
910
     * @param bool $disableNotification
911
     * @param string|null $parseMode
912
     *
913
     * @return \TelegramBot\Api\Types\Message
914
     * @throws \TelegramBot\Api\InvalidArgumentException
915
     * @throws \TelegramBot\Api\Exception
916
     */
917
    public function sendDocument(
918
        $chatId,
919
        $document,
920
        $caption = null,
921
        $replyToMessageId = null,
922
        $replyMarkup = null,
923
        $disableNotification = false,
924
        $parseMode = null
925
    ) {
926
        return Message::fromResponse($this->call('sendDocument', [
927
            'chat_id' => $chatId,
928
            'document' => $document,
929
            'caption' => $caption,
930
            'reply_to_message_id' => $replyToMessageId,
931
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
932
            'disable_notification' => (bool)$disableNotification,
933
            'parse_mode' => $parseMode
934
        ]));
935
    }
936
937
    /**
938
     * Use this method to get basic info about a file and prepare it for downloading.
939
     * For the moment, bots can download files of up to 20MB in size.
940
     * On success, a File object is returned.
941
     * The file can then be downloaded via the link https://api.telegram.org/file/bot<token>/<file_path>,
942
     * where <file_path> is taken from the response.
943
     * It is guaranteed that the link will be valid for at least 1 hour.
944
     * When the link expires, a new one can be requested by calling getFile again.
945
     *
946
     * @param $fileId
947
     *
948
     * @return \TelegramBot\Api\Types\File
949
     * @throws \TelegramBot\Api\InvalidArgumentException
950
     * @throws \TelegramBot\Api\Exception
951
     */
952
    public function getFile($fileId)
953
    {
954
        return File::fromResponse($this->call('getFile', ['file_id' => $fileId]));
955
    }
956
957
    /**
958
     * Get file contents via cURL
959
     *
960
     * @param $fileId
961
     *
962
     * @return string
963
     *
964
     * @throws \TelegramBot\Api\HttpException
965
     */
966
    public function downloadFile($fileId)
967
    {
968
        $file = $this->getFile($fileId);
969
        $options = [
970
            CURLOPT_HEADER => 0,
971
            CURLOPT_HTTPGET => 1,
972
            CURLOPT_RETURNTRANSFER => 1,
973
            CURLOPT_URL => $this->getFileUrl().'/'.$file->getFilePath(),
974
        ];
975
976
        return $this->executeCurl($options);
977
    }
978
979
    /**
980
     * Use this method to send answers to an inline query. On success, True is returned.
981
     * No more than 50 results per query are allowed.
982
     *
983
     * @param string $inlineQueryId
984
     * @param AbstractInlineQueryResult[] $results
985
     * @param int $cacheTime
986
     * @param bool $isPersonal
987
     * @param string $nextOffset
988
     * @param string $switchPmText
989
     * @param string $switchPmParameter
990
     *
991
     * @return mixed
992
     * @throws Exception
993
     */
994
    public function answerInlineQuery(
995
        $inlineQueryId,
996
        $results,
997
        $cacheTime = 300,
998
        $isPersonal = false,
999
        $nextOffset = '',
1000
        $switchPmText = null,
1001
        $switchPmParameter = null
1002
    ) {
1003
        $results = array_map(function ($item) {
1004
            /* @var AbstractInlineQueryResult $item */
1005
            return json_decode($item->toJson(), true);
1006
        }, $results);
1007
1008
        return $this->call('answerInlineQuery', [
1009
            'inline_query_id' => $inlineQueryId,
1010
            'results' => json_encode($results),
1011
            'cache_time' => $cacheTime,
1012
            'is_personal' => $isPersonal,
1013
            'next_offset' => $nextOffset,
1014
            'switch_pm_text' => $switchPmText,
1015
            'switch_pm_parameter' => $switchPmParameter,
1016
        ]);
1017
    }
1018
1019
    /**
1020
     * Use this method to kick a user from a group or a supergroup.
1021
     * In the case of supergroups, the user will not be able to return to the group
1022
     * on their own using invite links, etc., unless unbanned first.
1023
     * The bot must be an administrator in the group for this to work. Returns True on success.
1024
     *
1025
     * @param int|string $chatId Unique identifier for the target group
1026
     * or username of the target supergroup (in the format @supergroupusername)
1027
     * @param int $userId Unique identifier of the target user
1028
     * @param null|int $untilDate Date when the user will be unbanned, unix time.
1029
     *                            If user is banned for more than 366 days or less than 30 seconds from the current time
1030
     *                            they are considered to be banned forever
1031
     *
1032
     * @return bool
1033
     */
1034
    public function kickChatMember($chatId, $userId, $untilDate = null)
1035
    {
1036
        return $this->call('kickChatMember', [
1037
            'chat_id' => $chatId,
1038
            'user_id' => $userId,
1039
            'until_date' => $untilDate
1040
        ]);
1041
    }
1042
1043
    /**
1044
     * Use this method to unban a previously kicked user in a supergroup.
1045
     * The user will not return to the group automatically, but will be able to join via link, etc.
1046
     * The bot must be an administrator in the group for this to work. Returns True on success.
1047
     *
1048
     * @param int|string $chatId Unique identifier for the target group
1049
     * or username of the target supergroup (in the format @supergroupusername)
1050
     * @param int $userId Unique identifier of the target user
1051
     *
1052
     * @return bool
1053
     */
1054
    public function unbanChatMember($chatId, $userId)
1055
    {
1056
        return $this->call('unbanChatMember', [
1057
            'chat_id' => $chatId,
1058
            'user_id' => $userId,
1059
        ]);
1060
    }
1061
1062
    /**
1063
     * Use this method to send answers to callback queries sent from inline keyboards.
1064
     * The answer will be displayed to the user as a notification at the top of the chat screen or as an alert.
1065
     *
1066
     * @param $callbackQueryId
1067
     * @param null $text
1068
     * @param bool $showAlert
1069
     *
1070
     * @return bool
1071
     */
1072
    public function answerCallbackQuery($callbackQueryId, $text = null, $showAlert = false)
1073
    {
1074
        return $this->call('answerCallbackQuery', [
1075
            'callback_query_id' => $callbackQueryId,
1076
            'text' => $text,
1077
            'show_alert' => (bool)$showAlert,
1078
        ]);
1079
    }
1080
1081
1082
    /**
1083
     * Use this method to edit text messages sent by the bot or via the bot
1084
     *
1085
     * @param int|string $chatId
1086
     * @param int $messageId
1087
     * @param string $text
1088
     * @param string $inlineMessageId
1089
     * @param string|null $parseMode
1090
     * @param bool $disablePreview
1091
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
1092
     *        Types\ReplyKeyboardRemove|null $replyMarkup
1093
     * @return Message
1094
     */
1095
    public function editMessageText(
1096
        $chatId,
1097
        $messageId,
1098
        $text,
1099
        $parseMode = null,
1100
        $disablePreview = false,
1101
        $replyMarkup = null,
1102
        $inlineMessageId = null
1103
    ) {
1104
        return Message::fromResponse($this->call('editMessageText', [
1105
            'chat_id' => $chatId,
1106
            'message_id' => $messageId,
1107
            'text' => $text,
1108
            'inline_message_id' => $inlineMessageId,
1109
            'parse_mode' => $parseMode,
1110
            'disable_web_page_preview' => $disablePreview,
1111
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
1112
        ]));
1113
    }
1114
1115
    /**
1116
     * Use this method to edit text messages sent by the bot or via the bot
1117
     *
1118
     * @param int|string $chatId
1119
     * @param int $messageId
1120
     * @param string|null $caption
1121
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
1122
     *        Types\ReplyKeyboardRemove|null $replyMarkup
1123
     * @param string $inlineMessageId
1124
     *
1125
     * @return \TelegramBot\Api\Types\Message
1126
     * @throws \TelegramBot\Api\InvalidArgumentException
1127
     * @throws \TelegramBot\Api\Exception
1128
     */
1129 View Code Duplication
    public function editMessageCaption(
1130
        $chatId,
1131
        $messageId,
1132
        $caption = null,
1133
        $replyMarkup = null,
1134
        $inlineMessageId = null
1135
    ) {
1136
        return Message::fromResponse($this->call('editMessageCaption', [
1137
            'chat_id' => $chatId,
1138
            'message_id' => $messageId,
1139
            'inline_message_id' => $inlineMessageId,
1140
            'caption' => $caption,
1141
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
1142
        ]));
1143
    }
1144
1145
    /**
1146
     * Use this method to edit animation, audio, document, photo, or video messages.
1147
     * If a message is a part of a message album, then it can be edited only to a photo or a video.
1148
     * Otherwise, message type can be changed arbitrarily.
1149
     * When inline message is edited, new file can't be uploaded. Use previously uploaded file via its file_id or specify a URL.
1150
     * On success, if the edited message was sent by the bot, the edited Message is returned, otherwise True is returned
1151
     *
1152
     * @param $chatId
1153
     * @param $messageId
1154
     * @param InputMedia $media
1155
     * @param null $inlineMessageId
1156
     * @param null $replyMarkup
1157
     * @return bool|Message
1158
     * @throws Exception
1159
     * @throws HttpException
1160
     * @throws InvalidJsonException
1161
     */
1162 View Code Duplication
    public function editMessageMedia(
1163
        $chatId,
1164
        $messageId,
1165
        InputMedia $media,
1166
        $inlineMessageId = null,
1167
        $replyMarkup = null
1168
    ) {
1169
        return Message::fromResponse($this->call('editMessageMedia', [
1170
            'chat_id' => $chatId,
1171
            'message_id' => $messageId,
1172
            'inline_message_id' => $inlineMessageId,
1173
            'media' => $media->toJson(),
1174
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
1175
        ]));
1176
    }
1177
1178
    /**
1179
     * Use this method to edit only the reply markup of messages sent by the bot or via the bot
1180
     *
1181
     * @param int|string $chatId
1182
     * @param int $messageId
1183
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
1184
     *        Types\ReplyKeyboardRemove|null $replyMarkup
1185
     * @param string $inlineMessageId
1186
     *
1187
     * @return Message
1188
     */
1189
    public function editMessageReplyMarkup(
1190
        $chatId,
1191
        $messageId,
1192
        $replyMarkup = null,
1193
        $inlineMessageId = null
1194
    ) {
1195
        return Message::fromResponse($this->call('editMessageReplyMarkup', [
1196
            'chat_id' => $chatId,
1197
            'message_id' => $messageId,
1198
            'inline_message_id' => $inlineMessageId,
1199
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
1200
        ]));
1201
    }
1202
1203
    /**
1204
     * Use this method to delete a message, including service messages, with the following limitations:
1205
     *  - A message can only be deleted if it was sent less than 48 hours ago.
1206
     *  - Bots can delete outgoing messages in groups and supergroups.
1207
     *  - Bots granted can_post_messages permissions can delete outgoing messages in channels.
1208
     *  - If the bot is an administrator of a group, it can delete any message there.
1209
     *  - If the bot has can_delete_messages permission in a supergroup or a channel, it can delete any message there.
1210
     *
1211
     * @param int|string $chatId
1212
     * @param int $messageId
1213
     *
1214
     * @return bool
1215
     */
1216
    public function deleteMessage($chatId, $messageId)
1217
    {
1218
        return $this->call('deleteMessage', [
1219
            'chat_id' => $chatId,
1220
            'message_id' => $messageId,
1221
        ]);
1222
    }
1223
1224
    /**
1225
     * Close curl
1226
     */
1227 9
    public function __destruct()
1228
    {
1229 9
        $this->curl && curl_close($this->curl);
1230 9
    }
1231
1232
    /**
1233
     * @return string
1234
     */
1235
    public function getUrl()
1236
    {
1237
        return self::URL_PREFIX.$this->token;
1238
    }
1239
1240
    /**
1241
     * @return string
1242
     */
1243
    public function getFileUrl()
1244
    {
1245
        return self::FILE_URL_PREFIX.$this->token;
1246
    }
1247
1248
    /**
1249
     * @param \TelegramBot\Api\Types\Update $update
1250
     * @param string $eventName
1251
     *
1252
     * @throws \TelegramBot\Api\Exception
1253
     */
1254
    public function trackUpdate(Update $update, $eventName = 'Message')
1255
    {
1256
        if (!in_array($update->getUpdateId(), $this->trackedEvents)) {
1257
            $this->trackedEvents[] = $update->getUpdateId();
1258
1259
            $this->track($update->getMessage(), $eventName);
1260
1261
            if (count($this->trackedEvents) > self::MAX_TRACKED_EVENTS) {
1262
                $this->trackedEvents = array_slice($this->trackedEvents, round(self::MAX_TRACKED_EVENTS / 4));
1263
            }
1264
        }
1265
    }
1266
1267
    /**
1268
     * Wrapper for tracker
1269
     *
1270
     * @param \TelegramBot\Api\Types\Message $message
1271
     * @param string $eventName
1272
     *
1273
     * @throws \TelegramBot\Api\Exception
1274
     */
1275
    public function track(Message $message, $eventName = 'Message')
1276
    {
1277
        if ($this->tracker instanceof Botan) {
1278
            $this->tracker->track($message, $eventName);
1279
        }
1280
    }
1281
1282
    /**
1283
     * Use this method to send invoices. On success, the sent Message is returned.
1284
     *
1285
     * @param int|string $chatId
1286
     * @param string $title
1287
     * @param string $description
1288
     * @param string $payload
1289
     * @param string $providerToken
1290
     * @param string $startParameter
1291
     * @param string $currency
1292
     * @param array $prices
1293
     * @param string|null $photoUrl
1294
     * @param int|null $photoSize
1295
     * @param int|null $photoWidth
1296
     * @param int|null $photoHeight
1297
     * @param bool $needName
1298
     * @param bool $needPhoneNumber
1299
     * @param bool $needEmail
1300
     * @param bool $needShippingAddress
1301
     * @param bool $isFlexible
1302
     * @param int|null $replyToMessageId
1303
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
1304
     *        Types\ReplyKeyboardRemove|null $replyMarkup
1305
     * @param bool $disableNotification
1306
     * @param string|null $providerData
1307
     * @param bool $sendPhoneNumberToProvider
1308
     * @param bool $sendEmailToProvider
1309
     *
1310
     * @return Message
1311
     */
1312
    public function sendInvoice(
1313
        $chatId,
1314
        $title,
1315
        $description,
1316
        $payload,
1317
        $providerToken,
1318
        $startParameter,
1319
        $currency,
1320
        $prices,
1321
        $isFlexible = false,
1322
        $photoUrl = null,
1323
        $photoSize = null,
1324
        $photoWidth = null,
1325
        $photoHeight = null,
1326
        $needName = false,
1327
        $needPhoneNumber = false,
1328
        $needEmail = false,
1329
        $needShippingAddress = false,
1330
        $replyToMessageId = null,
1331
        $replyMarkup = null,
1332
        $disableNotification = false,
1333
        $providerData = null,
1334
        $sendPhoneNumberToProvider = false,
1335
        $sendEmailToProvider = false
1336
    ) {
1337
        return Message::fromResponse($this->call('sendInvoice', [
1338
            'chat_id' => $chatId,
1339
            'title' => $title,
1340
            'description' => $description,
1341
            'payload' => $payload,
1342
            'provider_token' => $providerToken,
1343
            'start_parameter' => $startParameter,
1344
            'currency' => $currency,
1345
            'prices' => json_encode($prices),
1346
            'is_flexible' => $isFlexible,
1347
            'photo_url' => $photoUrl,
1348
            'photo_size' => $photoSize,
1349
            'photo_width' => $photoWidth,
1350
            'photo_height' => $photoHeight,
1351
            'need_name' => $needName,
1352
            'need_phone_number' => $needPhoneNumber,
1353
            'need_email' => $needEmail,
1354
            'need_shipping_address' => $needShippingAddress,
1355
            'reply_to_message_id' => $replyToMessageId,
1356
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
1357
            'disable_notification' => (bool)$disableNotification,
1358
            'provider_data' => $providerData,
1359
            'send_phone_number_to_provider' => (bool)$sendPhoneNumberToProvider,
1360
            'send_email_to_provider' => (bool)$sendEmailToProvider
1361
        ]));
1362
    }
1363
1364
    /**
1365
     * If you sent an invoice requesting a shipping address and the parameter is_flexible was specified, the Bot API
1366
     * will send an Update with a shipping_query field to the bot. Use this method to reply to shipping queries.
1367
     * On success, True is returned.
1368
     *
1369
     * @param string $shippingQueryId
1370
     * @param bool $ok
1371
     * @param array $shipping_options
1372
     * @param null|string $errorMessage
1373
     *
1374
     * @return bool
1375
     *
1376
     */
1377
    public function answerShippingQuery($shippingQueryId, $ok = true, $shipping_options = [], $errorMessage = null)
1378
    {
1379
        return $this->call('answerShippingQuery', [
1380
            'shipping_query_id' => $shippingQueryId,
1381
            'ok' => (bool)$ok,
1382
            'shipping_options' => json_encode($shipping_options),
1383
            'error_message' => $errorMessage
1384
        ]);
1385
    }
1386
1387
    /**
1388
     * Use this method to respond to such pre-checkout queries. On success, True is returned.
1389
     * Note: The Bot API must receive an answer within 10 seconds after the pre-checkout query was sent.
1390
     *
1391
     * @param string $preCheckoutQueryId
1392
     * @param bool $ok
1393
     * @param null|string $errorMessage
1394
     *
1395
     * @return mixed
1396
     */
1397
    public function answerPreCheckoutQuery($preCheckoutQueryId, $ok = true, $errorMessage = null)
1398
    {
1399
        return $this->call('answerPreCheckoutQuery', [
1400
            'pre_checkout_query_id' => $preCheckoutQueryId,
1401
            'ok' => (bool)$ok,
1402
            'error_message' => $errorMessage
1403
        ]);
1404
    }
1405
1406
    /**
1407
     * Use this method to restrict a user in a supergroup.
1408
     * The bot must be an administrator in the supergroup for this to work and must have the appropriate admin rights.
1409
     * Pass True for all boolean parameters to lift restrictions from a user.
1410
     *
1411
     * @param string|int $chatId Unique identifier for the target chat or username of the target supergroup
1412
     *                   (in the format @supergroupusername)
1413
     * @param int $userId Unique identifier of the target user
1414
     * @param null|integer $untilDate Date when restrictions will be lifted for the user, unix time.
1415
     *                     If user is restricted for more than 366 days or less than 30 seconds from the current time,
1416
     *                     they are considered to be restricted forever
1417
     * @param bool $canSendMessages Pass True, if the user can send text messages, contacts, locations and venues
1418
     * @param bool $canSendMediaMessages No Pass True, if the user can send audios, documents, photos, videos,
1419
     *                                   video notes and voice notes, implies can_send_messages
1420
     * @param bool $canSendOtherMessages Pass True, if the user can send animations, games, stickers and
1421
     *                                   use inline bots, implies can_send_media_messages
1422
     * @param bool $canAddWebPagePreviews Pass True, if the user may add web page previews to their messages,
1423
     *                                    implies can_send_media_messages
1424
     *
1425
     * @return bool
1426
     */
1427
    public function restrictChatMember(
1428
        $chatId,
1429
        $userId,
1430
        $untilDate = null,
1431
        $canSendMessages = false,
1432
        $canSendMediaMessages = false,
1433
        $canSendOtherMessages = false,
1434
        $canAddWebPagePreviews = false
1435
    ) {
1436
        return $this->call('restrictChatMember', [
1437
            'chat_id' => $chatId,
1438
            'user_id' => $userId,
1439
            'until_date' => $untilDate,
1440
            'can_send_messages' => $canSendMessages,
1441
            'can_send_media_messages' => $canSendMediaMessages,
1442
            'can_send_other_messages' => $canSendOtherMessages,
1443
            'can_add_web_page_previews' => $canAddWebPagePreviews
1444
        ]);
1445
    }
1446
1447
    /**
1448
     * Use this method to promote or demote a user in a supergroup or a channel.
1449
     * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
1450
     * Pass False for all boolean parameters to demote a user.
1451
     *
1452
     * @param string|int $chatId Unique identifier for the target chat or username of the target supergroup
1453
     *                   (in the format @supergroupusername)
1454
     * @param int $userId Unique identifier of the target user
1455
     * @param bool $canChangeInfo Pass True, if the administrator can change chat title, photo and other settings
1456
     * @param bool $canPostMessages Pass True, if the administrator can create channel posts, channels only
1457
     * @param bool $canEditMessages Pass True, if the administrator can edit messages of other users, channels only
1458
     * @param bool $canDeleteMessages Pass True, if the administrator can delete messages of other users
1459
     * @param bool $canInviteUsers Pass True, if the administrator can invite new users to the chat
1460
     * @param bool $canRestrictMembers Pass True, if the administrator can restrict, ban or unban chat members
1461
     * @param bool $canPinMessages Pass True, if the administrator can pin messages, supergroups only
1462
     * @param bool $canPromoteMembers Pass True, if the administrator can add new administrators with a subset of his
1463
     *                                own privileges or demote administrators that he has promoted,directly or
1464
     *                                indirectly (promoted by administrators that were appointed by him)
1465
     *
1466
     * @return bool
1467
     */
1468
    public function promoteChatMember(
1469
        $chatId,
1470
        $userId,
1471
        $canChangeInfo = true,
1472
        $canPostMessages = true,
1473
        $canEditMessages = true,
1474
        $canDeleteMessages = true,
1475
        $canInviteUsers = true,
1476
        $canRestrictMembers = true,
1477
        $canPinMessages = true,
1478
        $canPromoteMembers = true
1479
    ) {
1480
        return $this->call('promoteChatMember', [
1481
            'chat_id' => $chatId,
1482
            'user_id' => $userId,
1483
            'can_change_info' => $canChangeInfo,
1484
            'can_post_messages' => $canPostMessages,
1485
            'can_edit_messages' => $canEditMessages,
1486
            'can_delete_messages' => $canDeleteMessages,
1487
            'can_invite_users' => $canInviteUsers,
1488
            'can_restrict_members' => $canRestrictMembers,
1489
            'can_pin_messages' => $canPinMessages,
1490
            'can_promote_members' => $canPromoteMembers
1491
        ]);
1492
    }
1493
1494
    /**
1495
     * Use this method to export an invite link to a supergroup or a channel.
1496
     * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
1497
     *
1498
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1499
     *                           (in the format @channelusername)
1500
     * @return string
1501
     */
1502
    public function exportChatInviteLink($chatId)
1503
    {
1504
        return $this->call('exportChatInviteLink', [
1505
            'chat_id' => $chatId
1506
        ]);
1507
    }
1508
1509
    /**
1510
     * Use this method to set a new profile photo for the chat. Photos can't be changed for private chats.
1511
     * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
1512
     *
1513
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1514
     *                           (in the format @channelusername)
1515
     * @param \CURLFile|string $photo New chat photo, uploaded using multipart/form-data
1516
     *
1517
     * @return bool
1518
     */
1519
    public function setChatPhoto($chatId, $photo)
1520
    {
1521
        return $this->call('setChatPhoto', [
1522
            'chat_id' => $chatId,
1523
            'photo' => $photo
1524
        ]);
1525
    }
1526
1527
    /**
1528
     * Use this method to delete a chat photo. Photos can't be changed for private chats.
1529
     * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
1530
     *
1531
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1532
     *                           (in the format @channelusername)
1533
     *
1534
     * @return bool
1535
     */
1536
    public function deleteChatPhoto($chatId)
1537
    {
1538
        return $this->call('deleteChatPhoto', [
1539
            'chat_id' => $chatId
1540
        ]);
1541
    }
1542
1543
    /**
1544
     * Use this method to change the title of a chat. Titles can't be changed for private chats.
1545
     * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
1546
     *
1547
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1548
     *                           (in the format @channelusername)
1549
     * @param string $title New chat title, 1-255 characters
1550
     *
1551
     * @return bool
1552
     */
1553
    public function setChatTitle($chatId, $title)
1554
    {
1555
        return $this->call('setChatTitle', [
1556
            'chat_id' => $chatId,
1557
            'title' => $title
1558
        ]);
1559
    }
1560
1561
    /**
1562
     * Use this method to change the description of a supergroup or a channel.
1563
     * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
1564
     *
1565
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1566
     *                   (in the format @channelusername)
1567
     * @param string|null $description New chat description, 0-255 characters
1568
     *
1569
     * @return bool
1570
     */
1571
    public function setChatDescription($chatId, $description = null)
1572
    {
1573
        return $this->call('setChatDescription', [
1574
            'chat_id' => $chatId,
1575
            'title' => $description
1576
        ]);
1577
    }
1578
1579
    /**
1580
     * Use this method to pin a message in a supergroup.
1581
     * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
1582
     *
1583
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1584
     *                   (in the format @channelusername)
1585
     * @param int $messageId Identifier of a message to pin
1586
     * @param bool $disableNotification
1587
     *
1588
     * @return bool
1589
     */
1590
    public function pinChatMessage($chatId, $messageId, $disableNotification = false)
1591
    {
1592
        return $this->call('pinChatMessage', [
1593
            'chat_id' => $chatId,
1594
            'message_id' => $messageId,
1595
            'disable_notification' => $disableNotification
1596
        ]);
1597
    }
1598
1599
    /**
1600
     * Use this method to unpin a message in a supergroup chat.
1601
     * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
1602
     *
1603
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1604
     *                   (in the format @channelusername)
1605
     *
1606
     * @return bool
1607
     */
1608
    public function unpinChatMessage($chatId)
1609
    {
1610
        return $this->call('unpinChatMessage', [
1611
            'chat_id' => $chatId
1612
        ]);
1613
    }
1614
1615
    /**
1616
     * Use this method to get up to date information about the chat
1617
     * (current name of the user for one-on-one conversations, current username of a user, group or channel, etc.).
1618
     *
1619
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1620
     *                   (in the format @channelusername)
1621
     *
1622
     * @return Chat
1623
     */
1624
    public function getChat($chatId)
1625
    {
1626
        return Chat::fromResponse($this->call('getChat', [
1627
            'chat_id' => $chatId
1628
        ]));
1629
    }
1630
1631
    /**
1632
     * Use this method to get information about a member of a chat.
1633
     *
1634
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1635
     *                   (in the format @channelusername)
1636
     * @param int $userId
1637
     *
1638
     * @return ChatMember
1639
     */
1640
    public function getChatMember($chatId, $userId)
1641
    {
1642
        return ChatMember::fromResponse($this->call('getChatMember', [
1643
            'chat_id' => $chatId,
1644
            'user_id' => $userId
1645
        ]));
1646
    }
1647
1648
    /**
1649
     * Use this method for your bot to leave a group, supergroup or channel.
1650
     *
1651
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1652
     *                   (in the format @channelusername)
1653
     *
1654
     * @return bool
1655
     */
1656
    public function leaveChat($chatId)
1657
    {
1658
        return $this->call('leaveChat', [
1659
            'chat_id' => $chatId
1660
        ]);
1661
    }
1662
1663
    /**
1664
     * Use this method to get the number of members in a chat.
1665
     *
1666
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1667
     *                   (in the format @channelusername)
1668
     *
1669
     * @return int
1670
     */
1671
    public function getChatMembersCount($chatId)
1672
    {
1673
        return $this->call(
1674
            'getChatMembersCount',
1675
            [
1676
                'chat_id' => $chatId
1677
            ]
1678
        );
1679
    }
1680
1681
    /**
1682
     * Use this method to get a list of administrators in a chat.
1683
     *
1684
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1685
     *                   (in the format @channelusername)
1686
     *
1687
     * @return array
1688
     */
1689
    public function getChatAdministrators($chatId)
1690
    {
1691
        return ArrayOfChatMemberEntity::fromResponse(
1692
            $this->call(
1693
                'getChatAdministrators',
1694
                [
1695
                    'chat_id' => $chatId
1696
                ]
1697
            )
1698
        );
1699
    }
1700
1701
    /**
1702
     * As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute long.
1703
     * Use this method to send video messages.
1704
     * On success, the sent Message is returned.
1705
     *
1706
     * @param int|string $chatId chat_id or @channel_name
1707
     * @param \CURLFile|string $videoNote
1708
     * @param int|null $duration
1709
     * @param int|null $length
1710
     * @param int|null $replyToMessageId
1711
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
1712
     *        Types\ReplyKeyboardRemove|null $replyMarkup
1713
     * @param bool $disableNotification
1714
     *
1715
     * @return \TelegramBot\Api\Types\Message
1716
     * @throws \TelegramBot\Api\InvalidArgumentException
1717
     * @throws \TelegramBot\Api\Exception
1718
     */
1719
    public function sendVideoNote(
1720
        $chatId,
1721
        $videoNote,
1722
        $duration = null,
1723
        $length = null,
1724
        $replyToMessageId = null,
1725
        $replyMarkup = null,
1726
        $disableNotification = false
1727
    ) {
1728
        return Message::fromResponse($this->call('sendVideoNote', [
1729
            'chat_id' => $chatId,
1730
            'video_note' => $videoNote,
1731
            'duration' => $duration,
1732
            'length' => $length,
1733
            'reply_to_message_id' => $replyToMessageId,
1734
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
1735
            'disable_notification' => (bool)$disableNotification
1736
        ]));
1737
    }
1738
1739
    /**
1740
     * Use this method to send a group of photos or videos as an album.
1741
     * On success, the sent \TelegramBot\Api\Types\Message is returned.
1742
     *
1743
     * @param int|string $chatId
1744
     * @param ArrayOfInputMedia $media
1745
     * @param int|null $replyToMessageId
1746
     * @param bool $disableNotification
1747
     *
1748
     * @return array
1749
     * @throws \TelegramBot\Api\Exception
1750
     */
1751
    public function sendMediaGroup(
1752
        $chatId,
1753
        $media,
1754
        $disableNotification = false,
1755
        $replyToMessageId = null
1756
    ) {
1757
        return ArrayOfMessages::fromResponse($this->call('sendMediaGroup', [
1758
            'chat_id' => $chatId,
1759
            'media' => $media->toJson(),
1760
            'reply_to_message_id' => (int)$replyToMessageId,
1761
            'disable_notification' => (bool)$disableNotification
1762
        ]));
1763
    }
1764
1765
    /**
1766
     * Enable proxy for curl requests. Empty string will disable proxy.
1767
     *
1768
     * @param string $proxyString
1769
     *
1770
     * @return BotApi
1771
     */
1772
    public function setProxy($proxyString = '', $socks5 = false)
1773
    {
1774
        if (empty($proxyString)) {
1775
            $this->proxySettings = [];
1776
            return $this;
1777
        }
1778
1779
        $this->proxySettings = [
1780
            CURLOPT_PROXY => $proxyString,
1781
            CURLOPT_HTTPPROXYTUNNEL => true,
1782
        ];
1783
1784
        if ($socks5) {
1785
            $this->proxySettings[CURLOPT_PROXYTYPE] = CURLPROXY_SOCKS5;
1786
        }
1787
        return $this;
1788
    }
1789
1790
1791
    /**
1792
     * Use this method to send a native poll. A native poll can't be sent to a private chat.
1793
     * On success, the sent \TelegramBot\Api\Types\Message is returned.
1794
     *
1795
     * @param int|string $chatId
1796
     * @param string $question
1797
     * @param array $options
1798
     * @param bool $disableNotification
1799
     * @param int|null $replyToMessageId
1800
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
1801
     *        Types\ReplyKeyboardRemove|null $replyMarkup
1802
     *
1803
     * @return \TelegramBot\Api\Types\Message
1804
     * @throws \TelegramBot\Api\InvalidArgumentException
1805
     * @throws \TelegramBot\Api\Exception
1806
     */
1807 View Code Duplication
    public function sendPoll(
1808
        $chatId,
1809
        $question,
1810
        $options,
1811
        $disableNotification = false,
1812
        $replyToMessageId = null,
1813
        $replyMarkup = null
1814
    ) {
1815
        return Message::fromResponse($this->call('sendPoll', [
1816
            'chat_id' => $chatId,
1817
            'question' => $question,
1818
            'options' => json_encode($options),
1819
            'disable_notification' => (bool)$disableNotification,
1820
            'reply_to_message_id' => (int)$replyToMessageId,
1821
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
1822
        ]));
1823
    }
1824
1825
    /**
1826
     * Use this method to stop a poll which was sent by the bot.
1827
     * On success, the stopped \TelegramBot\Api\Types\Poll with the final results is returned.
1828
     *
1829
     * @param int|string $chatId
1830
     * @param int $messageId
1831
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
1832
     *        Types\ReplyKeyboardRemove|null $replyMarkup
1833
     * @return Poll
1834
     * @throws \TelegramBot\Api\InvalidArgumentException
1835
     * @throws \TelegramBot\Api\Exception
1836
     */
1837
    public function stopPoll(
1838
        $chatId,
1839
        $messageId,
1840
        $replyMarkup = null
1841
    ) {
1842
        return Poll::fromResponse($this->call('stopPoll', [
1843
            'chat_id' => $chatId,
1844
            'message_id' => $messageId,
1845
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
1846
        ]));
1847
    }
1848
1849
    /**
1850
     * Set an option for a cURL transfer
1851
     *
1852
     * @param int $option The CURLOPT_XXX option to set
1853
     * @param mixed $value The value to be set on option
1854
     */
1855
    public function setCurlOption($option, $value)
1856
    {
1857
        $this->customCurlOptions[$option] = $value;
1858
    }
1859
1860
    /**
1861
     * Unset an option for a cURL transfer
1862
     *
1863
     * @param int $option The CURLOPT_XXX option to unset
1864
     */
1865
    public function unsetCurlOption($option)
1866
    {
1867
        unset($this->customCurlOptions[$option]);
1868
    }
1869
1870
    /**
1871
     * Clean custom options
1872
     */
1873
    public function resetCurlOptions()
1874
    {
1875
        $this->customCurlOptions = [];
1876
    }
1877
}
1878