Completed
Push — master ( 917978...9a65ac )
by Irfaq
02:22
created

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