Completed
Push — master ( c692a8...3329a0 )
by Irfaq
12:30 queued 10:17
created

Api::answerCallbackQuery()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
3
namespace Telegram\Bot;
4
5
use Illuminate\Contracts\Container\Container;
6
use Telegram\Bot\Commands\CommandBus;
7
use Telegram\Bot\Exceptions\TelegramSDKException;
8
use Telegram\Bot\FileUpload\InputFile;
9
use Telegram\Bot\HttpClients\GuzzleHttpClient;
10
use Telegram\Bot\HttpClients\HttpClientInterface;
11
use Telegram\Bot\Objects\File;
12
use Telegram\Bot\Objects\Message;
13
use Telegram\Bot\Objects\Update;
14
use Telegram\Bot\Objects\User;
15
use Telegram\Bot\Objects\UserProfilePhotos;
16
17
/**
18
 * Class Api.
19
 *
20
 * @mixin Commands\CommandBus
21
 */
22
class Api
23
{
24
    /**
25
     * @var string Version number of the Telegram Bot PHP SDK.
26
     */
27
    const VERSION = '3.0.0';
28
29
    /**
30
     * @var string The name of the environment variable that contains the Telegram Bot API Access Token.
31
     */
32
    const BOT_TOKEN_ENV_NAME = 'TELEGRAM_BOT_TOKEN';
33
34
    /**
35
     * @var TelegramClient The Telegram client service.
36
     */
37
    protected $client;
38
39
    /**
40
     * @var string Telegram Bot API Access Token.
41
     */
42
    protected $accessToken = null;
43
44
    /**
45
     * @var TelegramResponse|null Stores the last request made to Telegram Bot API.
46
     */
47
    protected $lastResponse;
48
49
    /**
50
     * @var bool Indicates if the request to Telegram will be asynchronous (non-blocking).
51
     */
52
    protected $isAsyncRequest = false;
53
54
    /**
55
     * @var CommandBus|null Telegram Command Bus.
56
     */
57
    protected $commandBus = null;
58
59
    /**
60
     * @var Container IoC Container
61
     */
62
    protected static $container = null;
63
64
    /**
65
     * Timeout of the request in seconds.
66
     *
67
     * @var int
68
     */
69
    protected $timeOut = 60;
70
71
    /**
72
     * Connection timeout of the request in seconds.
73
     *
74
     * @var int
75
     */
76
    protected $connectTimeOut = 10;
77
78
    /**
79
     * Instantiates a new Telegram super-class object.
80
     *
81
     *
82
     * @param string                     $token               The Telegram Bot API Access Token.
83
     * @param bool                       $async               (Optional) Indicates if the request to Telegram
84
     *                                                        will be asynchronous (non-blocking).
85
     * @param string|HttpClientInterface $http_client_handler (Optional) Custom HTTP Client Handler.
86
     *
87
     * @throws TelegramSDKException
88
     */
89 76
    public function __construct($token = null, $async = false, $http_client_handler = null)
90
    {
91 76
        $this->accessToken = isset($token) ? $token : getenv(static::BOT_TOKEN_ENV_NAME);
92 76
        if (!$this->accessToken) {
93 2
            throw new TelegramSDKException('Required "token" not supplied in config and could not find fallback environment variable "'.static::BOT_TOKEN_ENV_NAME.'"');
94
        }
95
96 76
        $httpClientHandler = null;
97 76
        if (isset($http_client_handler)) {
98 46
            if ($http_client_handler instanceof HttpClientInterface) {
99 42
                $httpClientHandler = $http_client_handler;
100 46
            } elseif ($http_client_handler === 'guzzle') {
101 2
                $httpClientHandler = new GuzzleHttpClient();
102 2
            } else {
103 2
                throw new \InvalidArgumentException('The HTTP Client Handler must be set to "guzzle", or be an instance of Telegram\Bot\HttpClients\HttpClientInterface');
104
            }
105 44
        }
106
107 76
        if (isset($async)) {
108 76
            $this->setAsyncRequest($async);
109 76
        }
110
111 76
        $this->client = new TelegramClient($httpClientHandler);
112 76
        $this->commandBus = new CommandBus($this);
113 76
    }
114
115
    /**
116
     * Returns the TelegramClient service.
117
     *
118
     * @return TelegramClient
119
     */
120 6
    public function getClient()
121
    {
122 6
        return $this->client;
123
    }
124
125
    /**
126
     * Returns Telegram Bot API Access Token.
127
     *
128
     * @return string
129
     */
130 42
    public function getAccessToken()
131
    {
132 42
        return $this->accessToken;
133
    }
134
135
    /**
136
     * Returns the last response returned from API request.
137
     *
138
     * @return TelegramResponse
139
     */
140 2
    public function getLastResponse()
141
    {
142 2
        return $this->lastResponse;
143
    }
144
145
    /**
146
     * Sets the bot access token to use with API requests.
147
     *
148
     * @param string $accessToken The bot access token to save.
149
     *
150
     * @throws \InvalidArgumentException
151
     *
152
     * @return Api
153
     */
154 8
    public function setAccessToken($accessToken)
155
    {
156 8
        if (is_string($accessToken)) {
157 2
            $this->accessToken = $accessToken;
158
159 2
            return $this;
160
        }
161
162 6
        throw new \InvalidArgumentException('The Telegram bot access token must be of type "string"');
163
    }
164
165
    /**
166
     * Make this request asynchronous (non-blocking).
167
     *
168
     * @param bool $isAsyncRequest
169
     *
170
     * @return Api
171
     */
172 76
    public function setAsyncRequest($isAsyncRequest)
173
    {
174 76
        $this->isAsyncRequest = $isAsyncRequest;
175
176 76
        return $this;
177
    }
178
179
    /**
180
     * Check if this is an asynchronous request (non-blocking).
181
     *
182
     * @return bool
183
     */
184 42
    public function isAsyncRequest()
185
    {
186 42
        return $this->isAsyncRequest;
187
    }
188
189
    /**
190
     * Returns SDK's Command Bus.
191
     *
192
     * @return CommandBus
193
     */
194 8
    public function getCommandBus()
195
    {
196 8
        return $this->commandBus;
197
    }
198
199
    /**
200
     * A simple method for testing your bot's auth token.
201
     * Returns basic information about the bot in form of a User object.
202
     *
203
     * @link https://core.telegram.org/bots/api#getme
204
     *
205
     * @return User
206
     */
207 4
    public function getMe()
208
    {
209 4
        $response = $this->post('getMe');
210
211 2
        return new User($response->getDecodedBody());
212
    }
213
214
    /**
215
     * Send text messages.
216
     *
217
     * <code>
218
     * $params = [
219
     *   'chat_id'                  => '',
220
     *   'text'                     => '',
221
     *   'parse_mode'               => '',
222
     *   'disable_web_page_preview' => '',
223
     *   'disable_notification'     => '',
224
     *   'reply_to_message_id'      => '',
225
     *   'reply_markup'             => '',
226
     * ];
227
     * </code>
228
     *
229
     * @link https://core.telegram.org/bots/api#sendmessage
230
     *
231
     * @param array    $params
232
     *
233
     * @var int|string $params ['chat_id']
234
     * @var string     $params ['text']
235
     * @var string     $params ['parse_mode']
236
     * @var bool       $params ['disable_web_page_preview']
237
     * @var bool       $params ['disable_notification']
238
     * @var int        $params ['reply_to_message_id']
239
     * @var string     $params ['reply_markup']
240
     *
241
     * @return Message
242
     */
243 4
    public function sendMessage(array $params)
244
    {
245 4
        $response = $this->post('sendMessage', $params);
246
247 4
        return new Message($response->getDecodedBody());
248
    }
249
250
    /**
251
     * Forward messages of any kind.
252
     *
253
     * <code>
254
     * $params = [
255
     *   'chat_id'              => '',
256
     *   'from_chat_id'         => '',
257
     *   'disable_notification' => '',
258
     *   'message_id'           => '',
259
     * ];
260
     * </code>
261
     *
262
     * @link https://core.telegram.org/bots/api#forwardmessage
263
     *
264
     * @param array    $params
265
     *
266
     * @var int|string $params ['chat_id']
267
     * @var int        $params ['from_chat_id']
268
     * @var bool       $params ['disable_notification']
269
     * @var int        $params ['message_id']
270
     *
271
     * @return Message
272
     */
273 2
    public function forwardMessage(array $params)
274
    {
275 2
        $response = $this->post('forwardMessage', $params);
276
277 2
        return new Message($response->getDecodedBody());
278
    }
279
280
    /**
281
     * Send Photos.
282
     *
283
     * <code>
284
     * $params = [
285
     *   'chat_id'              => '',
286
     *   'photo'                => '',
287
     *   'caption'              => '',
288
     *   'disable_notification' => '',
289
     *   'reply_to_message_id'  => '',
290
     *   'reply_markup'         => '',
291
     * ];
292
     * </code>
293
     *
294
     * @link https://core.telegram.org/bots/api#sendphoto
295
     *
296
     * @param array    $params
297
     *
298
     * @var int|string $params ['chat_id']
299
     * @var string     $params ['photo']
300
     * @var string     $params ['caption']
301
     * @var bool       $params ['disable_notification']
302
     * @var int        $params ['reply_to_message_id']
303
     * @var string     $params ['reply_markup']
304
     *
305
     * @return Message
306
     */
307 4
    public function sendPhoto(array $params)
308
    {
309 4
        return $this->uploadFile('sendPhoto', $params);
310
    }
311
312
    /**
313
     * Send regular audio files.
314
     *
315
     * <code>
316
     * $params = [
317
     *   'chat_id'              => '',
318
     *   'audio'                => '',
319
     *   'duration'             => '',
320
     *   'performer'            => '',
321
     *   'title'                => '',
322
     *   'disable_notification' => '',
323
     *   'reply_to_message_id'  => '',
324
     *   'reply_markup'         => '',
325
     * ];
326
     * </code>
327
     *
328
     * @link https://core.telegram.org/bots/api#sendaudio
329
     *
330
     * @param array    $params
331
     *
332
     * @var int|string $params ['chat_id']
333
     * @var string     $params ['audio']
334
     * @var int        $params ['duration']
335
     * @var string     $params ['performer']
336
     * @var string     $params ['title']
337
     * @var bool       $params ['disable_notification']
338
     * @var int        $params ['reply_to_message_id']
339
     * @var string     $params ['reply_markup']
340
     *
341
     * @return Message
342
     */
343 2
    public function sendAudio(array $params)
344
    {
345 2
        return $this->uploadFile('sendAudio', $params);
346
    }
347
348
    /**
349
     * Send general files.
350
     *
351
     * <code>
352
     * $params = [
353
     *   'chat_id'              => '',
354
     *   'document'             => '',
355
     *   'caption'              => '',
356
     *   'disable_notification' => '',
357
     *   'reply_to_message_id'  => '',
358
     *   'reply_markup'         => '',
359
     * ];
360
     * </code>
361
     *
362
     * @link https://core.telegram.org/bots/api#senddocument
363
     *
364
     * @param array    $params
365
     *
366
     * @var int|string $params ['chat_id']
367
     * @var string     $params ['document']
368
     * @var string     $params ['caption']
369
     * @var bool       $params ['disable_notification']
370
     * @var int        $params ['reply_to_message_id']
371
     * @var string     $params ['reply_markup']
372
     *
373
     * @return Message
374
     */
375 2
    public function sendDocument(array $params)
376
    {
377 2
        return $this->uploadFile('sendDocument', $params);
378
    }
379
380
    /**
381
     * Send .webp stickers.
382
     *
383
     * <code>
384
     * $params = [
385
     *   'chat_id'              => '',
386
     *   'sticker'              => '',
387
     *   'disable_notification' => '',
388
     *   'reply_to_message_id'  => '',
389
     *   'reply_markup'         => '',
390
     * ];
391
     * </code>
392
     *
393
     * @link https://core.telegram.org/bots/api#sendsticker
394
     *
395
     * @param array    $params
396
     *
397
     * @var int|string $params ['chat_id']
398
     * @var string     $params ['sticker']
399
     * @var bool       $params ['disable_notification']
400
     * @var int        $params ['reply_to_message_id']
401
     * @var string     $params ['reply_markup']
402
     *
403
     * @throws TelegramSDKException
404
     *
405
     * @return Message
406
     */
407 2
    public function sendSticker(array $params)
408
    {
409 2
        if (is_file($params['sticker']) && (pathinfo($params['sticker'], PATHINFO_EXTENSION) !== 'webp')) {
410
            throw new TelegramSDKException('Invalid Sticker Provided. Supported Format: Webp');
411
        }
412
413 2
        return $this->uploadFile('sendSticker', $params);
414
    }
415
416
    /**
417
     * Send Video File, Telegram clients support mp4 videos (other formats may be sent as Document).
418
     *
419
     * <code>
420
     * $params = [
421
     *   'chat_id'              => '',
422
     *   'video'                => '',
423
     *   'duration'             => '',
424
     *   'width'                => '',
425
     *   'height'               => '',
426
     *   'caption'              => '',
427
     *   'disable_notification' => '',
428
     *   'reply_to_message_id'  => '',
429
     *   'reply_markup'         => '',
430
     * ];
431
     * </code>
432
     *
433
     * @see  sendDocument
434
     * @link https://core.telegram.org/bots/api#sendvideo
435
     *
436
     * @param array    $params
437
     *
438
     * @var int|string $params ['chat_id']
439
     * @var string     $params ['video']
440
     * @var int        $params ['duration']
441
     * @var int        $params ['width']
442
     * @var int        $params ['height']
443
     * @var string     $params ['caption']
444
     * @var bool       $params ['disable_notification']
445
     * @var int        $params ['reply_to_message_id']
446
     * @var string     $params ['reply_markup']
447
     *
448
     * @return Message
449
     */
450 2
    public function sendVideo(array $params)
451
    {
452 2
        return $this->uploadFile('sendVideo', $params);
453
    }
454
455
    /**
456
     * Send voice audio files.
457
     *
458
     * <code>
459
     * $params = [
460
     *   'chat_id'              => '',
461
     *   'voice'                => '',
462
     *   'duration'             => '',
463
     *   'disable_notification' => '',
464
     *   'reply_to_message_id'  => '',
465
     *   'reply_markup'         => '',
466
     * ];
467
     * </code>
468
     *
469
     * @link https://core.telegram.org/bots/api#sendaudio
470
     *
471
     * @param array    $params
472
     *
473
     * @var int|string $params ['chat_id']
474
     * @var string     $params ['voice']
475
     * @var int        $params ['duration']
476
     * @var bool       $params ['disable_notification']
477
     * @var int        $params ['reply_to_message_id']
478
     * @var string     $params ['reply_markup']
479
     *
480
     * @return Message
481
     */
482 2
    public function sendVoice(array $params)
483
    {
484 2
        return $this->uploadFile('sendVoice', $params);
485
    }
486
487
    /**
488
     * Send point on the map.
489
     *
490
     * <code>
491
     * $params = [
492
     *   'chat_id'              => '',
493
     *   'latitude'             => '',
494
     *   'longitude'            => '',
495
     *   'disable_notification' => '',
496
     *   'reply_to_message_id'  => '',
497
     *   'reply_markup'         => '',
498
     * ];
499
     * </code>
500
     *
501
     * @link https://core.telegram.org/bots/api#sendlocation
502
     *
503
     * @param array    $params
504
     *
505
     * @var int|string $params ['chat_id']
506
     * @var float      $params ['latitude']
507
     * @var float      $params ['longitude']
508
     * @var bool       $params ['disable_notification']
509
     * @var int        $params ['reply_to_message_id']
510
     * @var string     $params ['reply_markup']
511
     *
512
     * @return Message
513
     */
514 2
    public function sendLocation(array $params)
515
    {
516 2
        $response = $this->post('sendLocation', $params);
517
518 2
        return new Message($response->getDecodedBody());
519
    }
520
521
    /**
522
     * Send information about a venue.
523
     *
524
     * <code>
525
     * $params = [
526
     *   'chat_id'              => '',
527
     *   'latitude'             => '',
528
     *   'longitude'            => '',
529
     *   'title'                => '',
530
     *   'address'              => '',
531
     *   'foursquare_id'        => '',
532
     *   'disable_notification' => '',
533
     *   'reply_to_message_id'  => '',
534
     *   'reply_markup'         => '',
535
     * ];
536
     * </code>
537
     *
538
     * @link https://core.telegram.org/bots/api#sendvenue
539
     *
540
     * @param array    $params
541
     *
542
     * @var int|string $params ['chat_id']
543
     * @var float      $params ['latitude']
544
     * @var float      $params ['longitude']
545
     * @var string     $params ['title']
546
     * @var string     $params ['address']
547
     * @var string     $params ['foursquare_id']
548
     * @var bool       $params ['disable_notification']
549
     * @var int        $params ['reply_to_message_id']
550
     * @var string     $params ['reply_markup']
551
     *
552
     * @return Message
553
     */
554
    public function sendVenue(array $params)
555
    {
556
        $response = $this->post('sendVenue', $params);
557
558
        return new Message($response->getDecodedBody());
559
    }
560
561
    /**
562
     * Send phone contacts.
563
     *
564
     * <code>
565
     * $params = [
566
     *   'chat_id'              => '',
567
     *   'phone_number'         => '',
568
     *   'first_name'           => '',
569
     *   'last_name'            => '',
570
     *   'disable_notification' => '',
571
     *   'reply_to_message_id'  => '',
572
     *   'reply_markup'         => '',
573
     * ];
574
     * </code>
575
     *
576
     * @link https://core.telegram.org/bots/api#sendcontact
577
     *
578
     * @param array    $params
579
     *
580
     * @var int|string $params ['chat_id']
581
     * @var string     $params ['phone_number']
582
     * @var string     $params ['first_name']
583
     * @var string     $params ['last_name']
584
     * @var bool       $params ['disable_notification']
585
     * @var int        $params ['reply_to_message_id']
586
     * @var string     $params ['reply_markup']
587
     *
588
     * @return Message
589
     */
590
    public function sendContact(array $params)
591
    {
592
        $response = $this->post('sendContact', $params);
593
594
        return new Message($response->getDecodedBody());
595
    }
596
597
    /**
598
     * Broadcast a Chat Action.
599
     *
600
     * <code>
601
     * $params = [
602
     *   'chat_id' => '',
603
     *   'action'  => '',
604
     * ];
605
     * </code>
606
     *
607
     * @link https://core.telegram.org/bots/api#sendchataction
608
     *
609
     * @param array    $params
610
     *
611
     * @var int|string $params ['chat_id']
612
     * @var string     $params ['action']
613
     *
614
     * @throws TelegramSDKException
615
     *
616
     * @return TelegramResponse
617
     */
618 4
    public function sendChatAction(array $params)
619
    {
620
        $validActions = [
621 4
            'typing',
622 4
            'upload_photo',
623 4
            'record_video',
624 4
            'upload_video',
625 4
            'record_audio',
626 4
            'upload_audio',
627 4
            'upload_document',
628 4
            'find_location',
629 4
        ];
630
631 4
        if (isset($params['action']) && in_array($params['action'], $validActions)) {
632 2
            return $this->post('sendChatAction', $params);
633
        }
634
635 2
        throw new TelegramSDKException('Invalid Action! Accepted value: '.implode(', ', $validActions));
636
    }
637
638
    /**
639
     * Returns a list of profile pictures for a user.
640
     *
641
     * <code>
642
     * $params = [
643
     *   'user_id' => '',
644
     *   'offset'  => '',
645
     *   'limit'   => '',
646
     * ];
647
     * </code>
648
     *
649
     * @link https://core.telegram.org/bots/api#getuserprofilephotos
650
     *
651
     * @param array $params
652
     *
653
     * @var int     $params ['user_id']
654
     * @var int     $params ['offset']
655
     * @var int     $params ['limit']
656
     *
657
     * @return UserProfilePhotos
658
     */
659
    public function getUserProfilePhotos(array $params)
660
    {
661
        $response = $this->post('getUserProfilePhotos', $params);
662
663
        return new UserProfilePhotos($response->getDecodedBody());
664
    }
665
666
    /**
667
     * Returns basic info about a file and prepare it for downloading.
668
     *
669
     * <code>
670
     * $params = [
671
     *   'file_id' => '',
672
     * ];
673
     * </code>
674
     *
675
     * The file can then be downloaded via the link
676
     * https://api.telegram.org/file/bot<token>/<file_path>,
677
     * where <file_path> is taken from the response.
678
     *
679
     * @link https://core.telegram.org/bots/api#getFile
680
     *
681
     * @param array $params
682
     *
683
     * @var string  $params ['file_id']
684
     *
685
     * @return File
686
     */
687 2
    public function getFile(array $params)
688
    {
689 2
        $response = $this->post('getFile', $params);
690
691 2
        return new File($response->getDecodedBody());
692
    }
693
694
    /**
695
     * Kick a user from a group or a supergroup.
696
     *
697
     * In the case of supergroups, the user will not be able to return to the group on their own using
698
     * invite links etc., unless unbanned first.
699
     *
700
     * The bot must be an administrator in the group for this to work.
701
     *
702
     * <code>
703
     * $params = [
704
     *   'chat_id'              => '',
705
     *   'user_id'              => '',
706
     * ];
707
     * </code>
708
     *
709
     * @link https://core.telegram.org/bots/api#kickchatmember
710
     *
711
     * @param array    $params
712
     *
713
     * @var int|string $params ['chat_id']
714
     * @var int        $params ['user_id']
715
     *
716
     * @return TelegramResponse
717
     */
718
    public function kickChatMember(array $params)
719
    {
720
        return $this->post('kickChatMember', $params);
721
    }
722
723
    /**
724
     * Unban a previously kicked user in a supergroup.
725
     *
726
     * The user will not return to the group automatically, but will be able to join via link, etc.
727
     *
728
     * The bot must be an administrator in the group for this to work.
729
     *
730
     * <code>
731
     * $params = [
732
     *   'chat_id'              => '',
733
     *   'user_id'              => '',
734
     * ];
735
     * </code>
736
     *
737
     * @link https://core.telegram.org/bots/api#unbanchatmember
738
     *
739
     * @param array    $params
740
     *
741
     * @var int|string $params ['chat_id']
742
     * @var int        $params ['user_id']
743
     *
744
     * @return TelegramResponse
745
     */
746
    public function unbanChatMember(array $params)
747
    {
748
        return $this->post('unbanChatMember', $params);
749
    }
750
751
    /**
752
     * Send answers to callback queries sent from inline keyboards.
753
     *
754
     * he answer will be displayed to the user as a notification at the top of the chat screen or as an alert.
755
     *
756
     * <code>
757
     * $params = [
758
     *   'callback_query_id'  => '',
759
     *   'text'               => '',
760
     *   'show_alert'         => '',
761
     * ];
762
     * </code>
763
     *
764
     * @link https://core.telegram.org/bots/api#answerCallbackQuery
765
     *
766
     * @param array $params
767
     *
768
     * @var string  $params ['callback_query_id']
769
     * @var string  $params ['text']
770
     * @var bool    $params ['show_alert']
771
     *
772
     * @return TelegramResponse
773
     */
774
    public function answerCallbackQuery(array $params)
775
    {
776
        return $this->post('answerCallbackQuery', $params);
777
    }
778
779
    /**
780
     * Edit text messages sent by the bot or via the bot (for inline bots).
781
     *
782
     * <code>
783
     * $params = [
784
     *   'chat_id'                  => '',
785
     *   'message_id'               => '',
786
     *   'inline_message_id'        => '',
787
     *   'text'                     => '',
788
     *   'parse_mode'               => '',
789
     *   'disable_web_page_preview' => '',
790
     *   'reply_markup'             => '',
791
     * ];
792
     * </code>
793
     *
794
     * @link https://core.telegram.org/bots/api#editMessageText
795
     *
796
     * @param array $params
797
     *
798
     * @var int|string $params ['chat_id']
799
     * @var int        $params ['message_id']
800
     * @var string     $params ['inline_message_id']
801
     * @var string     $params ['text']
802
     * @var string     $params ['parse_mode']
803
     * @var bool       $params ['disable_web_page_preview']
804
     * @var string     $params ['reply_markup']
805
     *
806
     * @return TelegramResponse
807
     */
808
    public function editMessageText(array $params)
809
    {
810
        $response = $this->post('editMessageText', $params);
811
812
        return new Message($response->getDecodedBody());
813
    }
814
815
    /**
816
     * Edit captions of messages sent by the bot or via the bot (for inline bots).
817
     *
818
     * <code>
819
     * $params = [
820
     *   'chat_id'                  => '',
821
     *   'message_id'               => '',
822
     *   'inline_message_id'        => '',
823
     *   'caption'                  => '',
824
     *   'reply_markup'             => '',
825
     * ];
826
     * </code>
827
     *
828
     * @link https://core.telegram.org/bots/api#editMessageCaption
829
     *
830
     * @param array $params
831
     *
832
     * @var int|string $params ['chat_id']
833
     * @var int        $params ['message_id']
834
     * @var string     $params ['inline_message_id']
835
     * @var string     $params ['caption']
836
     * @var string     $params ['reply_markup']
837
     *
838
     * @return TelegramResponse
839
     */
840
    public function editMessageCaption(array $params)
841
    {
842
        $response = $this->post('editMessageCaption', $params);
843
844
        return new Message($response->getDecodedBody());
845
    }
846
847
    /**
848
     * Edit only the reply markup of messages sent by the bot or via the bot (for inline bots).
849
     *
850
     * <code>
851
     * $params = [
852
     *   'chat_id'                  => '',
853
     *   'message_id'               => '',
854
     *   'inline_message_id'        => '',
855
     *   'reply_markup'             => '',
856
     * ];
857
     * </code>
858
     *
859
     * @link https://core.telegram.org/bots/api#editMessageReplyMarkup
860
     *
861
     * @param array $params
862
     *
863
     * @var int|string $params ['chat_id']
864
     * @var int        $params ['message_id']
865
     * @var string     $params ['inline_message_id']
866
     * @var string     $params ['reply_markup']
867
     *
868
     * @return TelegramResponse
869
     */
870
    public function editMessageReplyMarkup(array $params)
871
    {
872
        $response = $this->post('editMessageReplyMarkup', $params);
873
874
        return new Message($response->getDecodedBody());
875
    }
876
877
    /**
878
     * Set a Webhook to receive incoming updates via an outgoing webhook.
879
     *
880
     * <code>
881
     * $params = [
882
     *   'url'         => '',
883
     *   'certificate' => '',
884
     * ];
885
     * </code>
886
     *
887
     * @link https://core.telegram.org/bots/api#setwebhook
888
     *
889
     * @param array $params
890
     *
891
     * @var string  $params ['url']         HTTPS url to send updates to.
892
     * @var string  $params ['certificate'] Upload your public key certificate so that the root certificate in
893
     *                                      use can be checked.
894
     *
895
     * @throws TelegramSDKException
896
     *
897
     * @return TelegramResponse
898
     */
899 6
    public function setWebhook(array $params)
900
    {
901 6
        if (filter_var($params['url'], FILTER_VALIDATE_URL) === false) {
902 2
            throw new TelegramSDKException('Invalid URL Provided');
903
        }
904
905 4
        if (parse_url($params['url'], PHP_URL_SCHEME) !== 'https') {
906 2
            throw new TelegramSDKException('Invalid URL, should be a HTTPS url.');
907
        }
908
909 2
        return $this->uploadFile('setWebhook', $params);
910
    }
911
912
    /**
913
     * Returns webhook updates sent by Telegram.
914
     * Works only if you set a webhook.
915
     *
916
     * @see setWebhook
917
     *
918
     * @return Update
919
     */
920
    public function getWebhookUpdates()
921
    {
922
        $body = json_decode(file_get_contents('php://input'), true);
923
924
        return new Update($body);
925
    }
926
927
    /**
928
     * Removes the outgoing webhook (if any).
929
     *
930
     * @return TelegramResponse
931
     */
932 2
    public function removeWebhook()
933
    {
934 2
        $url = '';
935
936 2
        return $this->post('setWebhook', compact('url'));
937
    }
938
939
    /**
940
     * Use this method to receive incoming updates using long polling.
941
     *
942
     * <code>
943
     * $params = [
944
     *   'offset'  => '',
945
     *   'limit'   => '',
946
     *   'timeout' => '',
947
     * ];
948
     * </code>
949
     *
950
     * @link https://core.telegram.org/bots/api#getupdates
951
     *
952
     * @param array  $params
953
     *
954
     * @var int|null $params ['offset']
955
     * @var int|null $params ['limit']
956
     * @var int|null $params ['timeout']
957
     *
958
     * @return Update[]
959
     */
960 6
    public function getUpdates(array $params = [])
961
    {
962 6
        $response = $this->post('getUpdates', $params);
963 6
        $updates = $response->getDecodedBody();
964
965 6
        $data = [];
966 6
        if (isset($updates['result'])) {
967 6
            foreach ($updates['result'] as $update) {
968 6
                $data[] = new Update($update);
969 6
            }
970 6
        }
971
972 6
        return $data;
973
    }
974
975
    /**
976
     * Builds a custom keyboard markup.
977
     *
978
     * <code>
979
     * $params = [
980
     *   'keyboard'          => '',
981
     *   'resize_keyboard'   => '',
982
     *   'one_time_keyboard' => '',
983
     *   'selective'         => '',
984
     * ];
985
     * </code>
986
     *
987
     * @link https://core.telegram.org/bots/api#replykeyboardmarkup
988
     *
989
     * @param array $params
990
     *
991
     * @var array   $params ['keyboard']
992
     * @var bool    $params ['resize_keyboard']
993
     * @var bool    $params ['one_time_keyboard']
994
     * @var bool    $params ['selective']
995
     *
996
     * @return string
997
     */
998 2
    public function replyKeyboardMarkup(array $params)
999
    {
1000 2
        return json_encode($params);
1001
    }
1002
1003
    /**
1004
     * Hide the current custom keyboard and display the default letter-keyboard.
1005
     *
1006
     * <code>
1007
     * $params = [
1008
     *   'hide_keyboard' => true,
1009
     *   'selective'     => false,
1010
     * ];
1011
     * </code>
1012
     *
1013
     * @link https://core.telegram.org/bots/api#replykeyboardhide
1014
     *
1015
     * @param array $params
1016
     *
1017
     * @var bool    $params ['hide_keyboard']
1018
     * @var bool    $params ['selective']
1019
     *
1020
     * @return string
1021
     */
1022 2
    public static function replyKeyboardHide(array $params = [])
1023
    {
1024 2
        return json_encode(array_merge(['hide_keyboard' => true, 'selective' => false], $params));
1025
    }
1026
1027
    /**
1028
     * Display a reply interface to the user (act as if the user has selected the bot‘s message and tapped ’Reply').
1029
     *
1030
     * <code>
1031
     * $params = [
1032
     *   'force_reply' => true,
1033
     *   'selective'   => false,
1034
     * ];
1035
     * </code>
1036
     *
1037
     * @link https://core.telegram.org/bots/api#forcereply
1038
     *
1039
     * @param array $params
1040
     *
1041
     * @var bool    $params ['force_reply']
1042
     * @var bool    $params ['selective']
1043
     *
1044
     * @return string
1045
     */
1046 2
    public static function forceReply(array $params = [])
1047
    {
1048 2
        return json_encode(array_merge(['force_reply' => true, 'selective' => false], $params));
1049
    }
1050
1051
    /**
1052
     * Processes Inbound Commands.
1053
     *
1054
     * @param bool $webhook
1055
     *
1056
     * @return Update|Update[]
1057
     */
1058 6
    public function commandsHandler($webhook = false)
1059
    {
1060 6
        if ($webhook) {
1061
            $update = $this->getWebhookUpdates();
1062
            $this->processCommand($update);
1063
1064
            return $update;
1065
        }
1066
1067 6
        $updates = $this->getUpdates();
1068 6
        $highestId = -1;
1069
1070 6
        foreach ($updates as $update) {
1071 6
            $highestId = $update->getUpdateId();
1072 6
            $this->processCommand($update);
1073 6
        }
1074
1075
        //An update is considered confirmed as soon as getUpdates is called with an offset higher than its update_id.
1076 6
        if ($highestId != -1) {
1077 6
            $params = [];
1078 6
            $params['offset'] = $highestId + 1;
1079 6
            $params['limit'] = 1;
1080 6
            $this->getUpdates($params);
1081 6
        }
1082
1083 6
        return $updates;
1084
    }
1085
1086
    /**
1087
     * Check update object for a command and process.
1088
     *
1089
     * @param Update $update
1090
     */
1091 6
    protected function processCommand(Update $update)
1092
    {
1093 6
        $message = $update->getMessage();
1094
1095 6
        if ($message !== null && $message->has('text')) {
1096 6
            $this->getCommandBus()->handler($message->getText(), $update);
1097 6
        }
1098 6
    }
1099
1100
    /**
1101
     * Determine if a given type is the message.
1102
     *
1103
     * @param string         $type
1104
     * @param Update|Message $object
1105
     *
1106
     * @return bool
1107
     */
1108
    public function isMessageType($type, $object)
1109
    {
1110
        if ($object instanceof Update) {
1111
            $object = $object->getMessage();
1112
        }
1113
1114
        if ($object->has(strtolower($type))) {
1115
            return true;
1116
        }
1117
1118
        return $this->detectMessageType($object) === $type;
1119
    }
1120
1121
    /**
1122
     * Detect Message Type Based on Update or Message Object.
1123
     *
1124
     * @param Update|Message $object
1125
     *
1126
     * @return string|null
1127
     */
1128
    public function detectMessageType($object)
1129
    {
1130
        if ($object instanceof Update) {
1131
            $object = $object->getMessage();
1132
        }
1133
1134
        $types = [
1135
            'text',
1136
            'audio',
1137
            'document',
1138
            'photo',
1139
            'sticker',
1140
            'video',
1141
            'voice',
1142
            'contact',
1143
            'location',
1144
            'venue',
1145
            'new_chat_member',
1146
            'left_chat_member',
1147
            'new_chat_title',
1148
            'new_chat_photo',
1149
            'delete_chat_photo',
1150
            'group_chat_created',
1151
            'supergroup_chat_created',
1152
            'channel_chat_created',
1153
            'migrate_to_chat_id',
1154
            'migrate_from_chat_id',
1155
            'pinned_message',
1156
        ];
1157
1158
        return $object->keys()
1159
            ->intersect($types)
1160
            ->pop();
1161
    }
1162
1163
    /**
1164
     * Sends a GET request to Telegram Bot API and returns the result.
1165
     *
1166
     * @param string $endpoint
1167
     * @param array  $params
1168
     *
1169
     * @throws TelegramSDKException
1170
     *
1171
     * @return TelegramResponse
1172
     */
1173
    protected function get($endpoint, $params = [])
1174
    {
1175
        return $this->sendRequest(
1176
            'GET',
1177
            $endpoint,
1178
            $params
1179
        );
1180
    }
1181
1182
    /**
1183
     * Sends a POST request to Telegram Bot API and returns the result.
1184
     *
1185
     * @param string $endpoint
1186
     * @param array  $params
1187
     * @param bool   $fileUpload Set true if a file is being uploaded.
1188
     *
1189
     * @return TelegramResponse
1190
     */
1191 40
    protected function post($endpoint, array $params = [], $fileUpload = false)
1192
    {
1193 40
        if ($fileUpload) {
1194 16
            $params = ['multipart' => $params];
1195 16
        } else {
1196 24
            $params = ['form_params' => $params];
1197
        }
1198
1199 40
        return $this->sendRequest(
1200 40
            'POST',
1201 40
            $endpoint,
1202
            $params
1203 40
        );
1204
    }
1205
1206
    /**
1207
     * Sends a multipart/form-data request to Telegram Bot API and returns the result.
1208
     * Used primarily for file uploads.
1209
     *
1210
     * @param string $endpoint
1211
     * @param array  $params
1212
     *
1213
     * @throws TelegramSDKException
1214
     *
1215
     * @return Message
1216
     */
1217 16
    protected function uploadFile($endpoint, array $params = [])
1218
    {
1219 16
        $i = 0;
1220 16
        $multipart_params = [];
1221 16
        foreach ($params as $name => $contents) {
1222 16
            if (is_null($contents)) {
1223
                continue;
1224
            }
1225
1226 16
            if (!is_resource($contents) && $name !== 'url') {
1227 14
                $validUrl = filter_var($contents, FILTER_VALIDATE_URL);
1228 14
                $contents = (is_file($contents) || $validUrl) ? (new InputFile($contents))->open() : (string)$contents;
1229 14
            }
1230
1231 16
            $multipart_params[$i]['name'] = $name;
1232 16
            $multipart_params[$i]['contents'] = $contents;
1233 16
            ++$i;
1234 16
        }
1235
1236 16
        $response = $this->post($endpoint, $multipart_params, true);
1237
1238 16
        return new Message($response->getDecodedBody());
1239
    }
1240
1241
    /**
1242
     * Sends a request to Telegram Bot API and returns the result.
1243
     *
1244
     * @param string $method
1245
     * @param string $endpoint
1246
     * @param array  $params
1247
     *
1248
     * @throws TelegramSDKException
1249
     *
1250
     * @return TelegramResponse
1251
     */
1252 40
    protected function sendRequest(
1253
        $method,
1254
        $endpoint,
1255
        array $params = []
1256
    ) {
1257 40
        $request = $this->request($method, $endpoint, $params);
1258
1259 40
        return $this->lastResponse = $this->client->sendRequest($request);
1260
    }
1261
1262
    /**
1263
     * Instantiates a new TelegramRequest entity.
1264
     *
1265
     * @param string $method
1266
     * @param string $endpoint
1267
     * @param array  $params
1268
     *
1269
     * @return TelegramRequest
1270
     */
1271 40
    protected function request(
1272
        $method,
1273
        $endpoint,
1274
        array $params = []
1275
    ) {
1276 40
        return new TelegramRequest(
1277 40
            $this->getAccessToken(),
1278 40
            $method,
1279 40
            $endpoint,
1280 40
            $params,
1281 40
            $this->isAsyncRequest(),
1282 40
            $this->getTimeOut(),
1283 40
            $this->getConnectTimeOut()
1284 40
        );
1285
    }
1286
1287
    /**
1288
     * Magic method to process any "get" requests.
1289
     *
1290
     * @param $method
1291
     * @param $arguments
1292
     *
1293
     * @return bool|TelegramResponse
1294
     */
1295 2
    public function __call($method, $arguments)
1296
    {
1297 2
        if (preg_match('/^\w+Commands?/', $method, $matches)) {
1298 2
            return call_user_func_array([$this->getCommandBus(), $matches[0]], $arguments);
1299
        }
1300
1301
        $action = substr($method, 0, 3);
1302
        if ($action === 'get') {
1303
            /* @noinspection PhpUndefinedFunctionInspection */
1304
            $class_name = studly_case(substr($method, 3));
1305
            $class = 'Telegram\Bot\Objects\\'.$class_name;
1306
            $response = $this->post($method, $arguments[0] ?: []);
1307
1308
            if (class_exists($class)) {
1309
                return new $class($response->getDecodedBody());
1310
            }
1311
1312
            return $response;
1313
        }
1314
1315
        return false;
1316
    }
1317
1318
    /**
1319
     * Set the IoC Container.
1320
     *
1321
     * @param $container Container instance
1322
     *
1323
     * @return void
1324
     */
1325 2
    public static function setContainer(Container $container)
1326
    {
1327 2
        self::$container = $container;
1328 2
    }
1329
1330
    /**
1331
     * Get the IoC Container.
1332
     *
1333
     * @return Container
1334
     */
1335 2
    public function getContainer()
1336
    {
1337 2
        return self::$container;
1338
    }
1339
1340
    /**
1341
     * Check if IoC Container has been set.
1342
     *
1343
     * @return boolean
1344
     */
1345
    public function hasContainer()
1346
    {
1347
        return self::$container !== null;
1348
    }
1349
1350
    /**
1351
     * @return int
1352
     */
1353 40
    public function getTimeOut()
1354
    {
1355 40
        return $this->timeOut;
1356
    }
1357
1358
    /**
1359
     * @param int $timeOut
1360
     *
1361
     * @return $this
1362
     */
1363 2
    public function setTimeOut($timeOut)
1364
    {
1365 2
        $this->timeOut = $timeOut;
1366
1367 2
        return $this;
1368
    }
1369
1370
    /**
1371
     * @return int
1372
     */
1373 40
    public function getConnectTimeOut()
1374
    {
1375 40
        return $this->connectTimeOut;
1376
    }
1377
1378
    /**
1379
     * @param int $connectTimeOut
1380
     *
1381
     * @return $this
1382
     */
1383 2
    public function setConnectTimeOut($connectTimeOut)
1384
    {
1385 2
        $this->connectTimeOut = $connectTimeOut;
1386
1387 2
        return $this;
1388
    }
1389
1390
    /**
1391
     * Use this method to send answers to an inline query.
1392
     *
1393
     * <code>
1394
     * $params = [
1395
     *   'inline_query_id'      => '',
1396
     *   'results'              => [],
1397
     *   'cache_time'           => 0,
1398
     *   'is_personal'          => false,
1399
     *   'next_offset'          => '',
1400
     *   'switch_pm_text'       => '',
1401
     *   'switch_pm_parameter'  => '',
1402
     * ];
1403
     * </code>
1404
     *
1405
     * @link https://core.telegram.org/bots/api#answerinlinequery
1406
     *
1407
     * @param array     $params
1408
     *
1409
     * @var string      $params ['inline_query_id']
1410
     * @var array       $params ['results']
1411
     * @var int|null    $params ['cache_time']
1412
     * @var bool|null   $params ['is_personal']
1413
     * @var string|null $params ['next_offset']
1414
     * @var string|null $params ['switch_pm_text']
1415
     * @var string|null $params ['switch_pm_parameter']
1416
     *
1417
     * @return bool
1418
     */
1419
    public function answerInlineQuery(array $params = [])
1420
    {
1421
        if (is_array($params['results'])) {
1422
            $params['results'] = json_encode($params['results']);
1423
        }
1424
1425
        return $this->post('answerInlineQuery', $params);
1426
    }
1427
}
1428