Passed
Pull Request — master (#251)
by
unknown
02:24
created

BotApi::sendInvoice()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 51

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 51
ccs 0
cts 25
cp 0
rs 9.069
c 0
b 0
f 0
cc 2
nc 1
nop 23
crap 6

How to fix   Long Method    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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