Completed
Pull Request — master (#171)
by
unknown
02:33
created

Api::processConversation()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 8
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 8
loc 8
ccs 0
cts 6
cp 0
rs 9.4285
cc 3
eloc 4
nc 2
nop 1
crap 12
1
<?php
2
3
namespace Telegram\Bot;
4
5
use Illuminate\Contracts\Container\Container;
6
use Telegram\Bot\Commands\CommandBus;
7
use Telegram\Bot\Conversations\ConversationBus;
8
use Telegram\Bot\Exceptions\TelegramSDKException;
9
use Telegram\Bot\FileUpload\InputFile;
10
use Telegram\Bot\HttpClients\GuzzleHttpClient;
11
use Telegram\Bot\HttpClients\HttpClientInterface;
12
use Telegram\Bot\Objects\File;
13
use Telegram\Bot\Objects\Message;
14
use Telegram\Bot\Objects\UnknownObject;
15
use Telegram\Bot\Objects\Update;
16
use Telegram\Bot\Objects\User;
17
use Telegram\Bot\Objects\UserProfilePhotos;
18
use Telegram\Bot\Keyboard\Keyboard;
19
use Telegram\Bot\Helpers\Emojify;
20
21
/**
22
 * Class Api.
23
 *
24
 * @mixin Commands\CommandBus
25
 */
26
class Api
27
{
28
    /**
29
     * @var string Version number of the Telegram Bot PHP SDK.
30
     */
31
    const VERSION = '3.0.0';
32
33
    /**
34
     * @var string The name of the environment variable that contains the Telegram Bot API Access Token.
35
     */
36
    const BOT_TOKEN_ENV_NAME = 'TELEGRAM_BOT_TOKEN';
37
38
    /**
39
     * @var TelegramClient The Telegram client service.
40
     */
41
    protected $client;
42
43
    /**
44
     * @var string Telegram Bot API Access Token.
45
     */
46
    protected $accessToken = null;
47
48
    /**
49
     * @var TelegramResponse|null Stores the last request made to Telegram Bot API.
50
     */
51
    protected $lastResponse;
52
53
    /**
54
     * @var bool Indicates if the request to Telegram will be asynchronous (non-blocking).
55
     */
56
    protected $isAsyncRequest = false;
57
58
    /**
59
     * @var CommandBus|null Telegram Command Bus.
60
     */
61
    protected $commandBus = null;
62
63
    /**
64
     * @var ConversationBus|null Telegram Command Bus.
65
     */
66
    protected $conversationBus = null;
67
68
    /**
69
     * @var Container IoC Container
70
     */
71
    protected static $container = null;
72
73
    /**
74
     * Timeout of the request in seconds.
75
     *
76
     * @var int
77
     */
78
    protected $timeOut = 60;
79
80
    /**
81
     * Connection timeout of the request in seconds.
82
     *
83
     * @var int
84
     */
85
    protected $connectTimeOut = 10;
86
87
    /**
88
     * Use Emojify for text fields in requests.
89
     *
90
     * @var bool
91
     */
92
    protected $useEmojify = true;
93
94
    /**
95
     * Instantiates a new Telegram super-class object.
96
     *
97
     *
98
     * @param string              $token                      The Telegram Bot API Access Token.
99
     * @param bool                $async                      (Optional) Indicates if the request to Telegram
100
     *                                                        will be asynchronous (non-blocking).
101
     * @param HttpClientInterface $httpClientHandler          (Optional) Custom HTTP Client Handler.
102
     *
103
     * @throws TelegramSDKException
104
     */
105 68
    public function __construct($token = null, $async = false, $httpClientHandler = null)
106
    {
107 68
        $this->accessToken = isset($token) ? $token : getenv(static::BOT_TOKEN_ENV_NAME);
108 68
        if (!$this->accessToken) {
109 2
            throw new TelegramSDKException('Required "token" not supplied in config and could not find fallback environment variable "'.static::BOT_TOKEN_ENV_NAME.'"');
110
        }
111
112 68
        if (isset($async)) {
113 68
            $this->setAsyncRequest($async);
114 68
        }
115
116 68
        $this->client = new TelegramClient($httpClientHandler);
117 68
        $this->commandBus = new CommandBus($this);
118 68
        $this->conversationBus = new ConversationBus($this);
119 68
    }
120
121
    /**
122
     * Invoke Bots Manager.
123
     *
124
     * @param $config
125
     *
126
     * @return BotsManager
127
     */
128
    public static function manager($config)
129
    {
130
        return new BotsManager($config);
131
    }
132
133
    /**
134
     * Returns the TelegramClient service.
135
     *
136
     * @return TelegramClient
137
     */
138 6
    public function getClient()
139
    {
140 6
        return $this->client;
141
    }
142
143
    /**
144
     * Returns Telegram Bot API Access Token.
145
     *
146
     * @return string
147
     */
148 42
    public function getAccessToken()
149
    {
150 42
        return $this->accessToken;
151
    }
152
153
    /**
154
     * Returns the last response returned from API request.
155
     *
156
     * @return TelegramResponse
157
     */
158 2
    public function getLastResponse()
159
    {
160 2
        return $this->lastResponse;
161
    }
162
163
    /**
164
     * Sets the bot access token to use with API requests.
165
     *
166
     * @param string $accessToken The bot access token to save.
167
     *
168
     * @throws \InvalidArgumentException
169
     *
170
     * @return Api
171
     */
172 8
    public function setAccessToken($accessToken)
173
    {
174 8
        if (is_string($accessToken)) {
175 2
            $this->accessToken = $accessToken;
176
177 2
            return $this;
178
        }
179
180 6
        throw new \InvalidArgumentException('The Telegram bot access token must be of type "string"');
181
    }
182
183
    /**
184
     * Make this request asynchronous (non-blocking).
185
     *
186
     * @param bool $isAsyncRequest
187
     *
188
     * @return Api
189
     */
190 68
    public function setAsyncRequest($isAsyncRequest)
191
    {
192 68
        $this->isAsyncRequest = $isAsyncRequest;
193
194 68
        return $this;
195
    }
196
197
    /**
198
     * Check if this is an asynchronous request (non-blocking).
199
     *
200
     * @return bool
201
     */
202 42
    public function isAsyncRequest()
203
    {
204 42
        return $this->isAsyncRequest;
205
    }
206
207
    /**
208
     * Returns SDK's Command Bus.
209
     *
210
     * @return CommandBus
211
     */
212 8
    public function getCommandBus()
213
    {
214 8
        return $this->commandBus;
215
    }
216
217
    /**
218
     * @return null|ConversationBus
219
     */
220
    public function getConversationBus()
221
    {
222
        return $this->conversationBus;
223
    }
224
225
    /**
226
     * A simple method for testing your bot's auth token.
227
     * Returns basic information about the bot in form of a User object.
228
     *
229
     * @link https://core.telegram.org/bots/api#getme
230
     *
231
     * @return User
232
     */
233 4
    public function getMe()
234
    {
235 4
        $response = $this->post('getMe');
236
237 2
        return new User($response->getDecodedBody());
238
    }
239
240
    /**
241
     * Send text messages.
242
     *
243
     * <code>
244
     * $params = [
245
     *   'chat_id'                  => '',
246
     *   'text'                     => '',
247
     *   'parse_mode'               => '',
248
     *   'disable_web_page_preview' => '',
249
     *   'disable_notification'     => '',
250
     *   'reply_to_message_id'      => '',
251
     *   'reply_markup'             => '',
252
     * ];
253
     * </code>
254
     *
255
     * @link https://core.telegram.org/bots/api#sendmessage
256
     *
257
     * @param array    $params
258
     *
259
     * @var int|string $params ['chat_id']
260
     * @var string     $params ['text']
261
     * @var string     $params ['parse_mode']
262
     * @var bool       $params ['disable_web_page_preview']
263
     * @var bool       $params ['disable_notification']
264
     * @var int        $params ['reply_to_message_id']
265
     * @var string     $params ['reply_markup']
266
     *
267
     * @return Message
268
     */
269 4 View Code Duplication
    public function sendMessage(array $params)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
270
    {
271 4
        $params = $this->emojify($params, 'text');
272 4
        $response = $this->post('sendMessage', $params);
273
274 4
        return new Message($response->getDecodedBody());
275
    }
276
277
    /**
278
     * Forward messages of any kind.
279
     *
280
     * <code>
281
     * $params = [
282
     *   'chat_id'              => '',
283
     *   'from_chat_id'         => '',
284
     *   'disable_notification' => '',
285
     *   'message_id'           => '',
286
     * ];
287
     * </code>
288
     *
289
     * @link https://core.telegram.org/bots/api#forwardmessage
290
     *
291
     * @param array    $params
292
     *
293
     * @var int|string $params ['chat_id']
294
     * @var int        $params ['from_chat_id']
295
     * @var bool       $params ['disable_notification']
296
     * @var int        $params ['message_id']
297
     *
298
     * @return Message
299
     */
300 2
    public function forwardMessage(array $params)
301
    {
302 2
        $response = $this->post('forwardMessage', $params);
303
304 2
        return new Message($response->getDecodedBody());
305
    }
306
307
    /**
308
     * Send Photos.
309
     *
310
     * <code>
311
     * $params = [
312
     *   'chat_id'              => '',
313
     *   'photo'                => '',
314
     *   'caption'              => '',
315
     *   'disable_notification' => '',
316
     *   'reply_to_message_id'  => '',
317
     *   'reply_markup'         => '',
318
     * ];
319
     * </code>
320
     *
321
     * @link https://core.telegram.org/bots/api#sendphoto
322
     *
323
     * @param array    $params
324
     *
325
     * @var int|string $params ['chat_id']
326
     * @var string     $params ['photo']
327
     * @var string     $params ['caption']
328
     * @var bool       $params ['disable_notification']
329
     * @var int        $params ['reply_to_message_id']
330
     * @var string     $params ['reply_markup']
331
     *
332
     * @return Message
333
     */
334 4
    public function sendPhoto(array $params)
335
    {
336 4
        $params = $this->emojify($params, 'caption');
337
338 4
        return $this->uploadFile('sendPhoto', $params);
339
    }
340
341
    /**
342
     * Send regular audio files.
343
     *
344
     * <code>
345
     * $params = [
346
     *   'chat_id'              => '',
347
     *   'audio'                => '',
348
     *   'duration'             => '',
349
     *   'performer'            => '',
350
     *   'title'                => '',
351
     *   'disable_notification' => '',
352
     *   'reply_to_message_id'  => '',
353
     *   'reply_markup'         => '',
354
     * ];
355
     * </code>
356
     *
357
     * @link https://core.telegram.org/bots/api#sendaudio
358
     *
359
     * @param array    $params
360
     *
361
     * @var int|string $params ['chat_id']
362
     * @var string     $params ['audio']
363
     * @var int        $params ['duration']
364
     * @var string     $params ['performer']
365
     * @var string     $params ['title']
366
     * @var bool       $params ['disable_notification']
367
     * @var int        $params ['reply_to_message_id']
368
     * @var string     $params ['reply_markup']
369
     *
370
     * @return Message
371
     */
372 2
    public function sendAudio(array $params)
373
    {
374 2
        return $this->uploadFile('sendAudio', $params);
375
    }
376
377
    /**
378
     * Send general files.
379
     *
380
     * <code>
381
     * $params = [
382
     *   'chat_id'              => '',
383
     *   'document'             => '',
384
     *   'caption'              => '',
385
     *   'disable_notification' => '',
386
     *   'reply_to_message_id'  => '',
387
     *   'reply_markup'         => '',
388
     * ];
389
     * </code>
390
     *
391
     * @link https://core.telegram.org/bots/api#senddocument
392
     *
393
     * @param array    $params
394
     *
395
     * @var int|string $params ['chat_id']
396
     * @var string     $params ['document']
397
     * @var string     $params ['caption']
398
     * @var bool       $params ['disable_notification']
399
     * @var int        $params ['reply_to_message_id']
400
     * @var string     $params ['reply_markup']
401
     *
402
     * @return Message
403
     */
404 2
    public function sendDocument(array $params)
405
    {
406 2
        $params = $this->emojify($params, 'caption');
407
408 2
        return $this->uploadFile('sendDocument', $params);
409
    }
410
411
    /**
412
     * Send .webp stickers.
413
     *
414
     * <code>
415
     * $params = [
416
     *   'chat_id'              => '',
417
     *   'sticker'              => '',
418
     *   'disable_notification' => '',
419
     *   'reply_to_message_id'  => '',
420
     *   'reply_markup'         => '',
421
     * ];
422
     * </code>
423
     *
424
     * @link https://core.telegram.org/bots/api#sendsticker
425
     *
426
     * @param array    $params
427
     *
428
     * @var int|string $params ['chat_id']
429
     * @var string     $params ['sticker']
430
     * @var bool       $params ['disable_notification']
431
     * @var int        $params ['reply_to_message_id']
432
     * @var string     $params ['reply_markup']
433
     *
434
     * @throws TelegramSDKException
435
     *
436
     * @return Message
437
     */
438 2
    public function sendSticker(array $params)
439
    {
440 2
        if (is_file($params['sticker']) && (pathinfo($params['sticker'], PATHINFO_EXTENSION) !== 'webp')) {
441
            throw new TelegramSDKException('Invalid Sticker Provided. Supported Format: Webp');
442
        }
443
444 2
        return $this->uploadFile('sendSticker', $params);
445
    }
446
447
    /**
448
     * Send Video File, Telegram clients support mp4 videos (other formats may be sent as Document).
449
     *
450
     * <code>
451
     * $params = [
452
     *   'chat_id'              => '',
453
     *   'video'                => '',
454
     *   'duration'             => '',
455
     *   'width'                => '',
456
     *   'height'               => '',
457
     *   'caption'              => '',
458
     *   'disable_notification' => '',
459
     *   'reply_to_message_id'  => '',
460
     *   'reply_markup'         => '',
461
     * ];
462
     * </code>
463
     *
464
     * @see  sendDocument
465
     * @link https://core.telegram.org/bots/api#sendvideo
466
     *
467
     * @param array    $params
468
     *
469
     * @var int|string $params ['chat_id']
470
     * @var string     $params ['video']
471
     * @var int        $params ['duration']
472
     * @var int        $params ['width']
473
     * @var int        $params ['height']
474
     * @var string     $params ['caption']
475
     * @var bool       $params ['disable_notification']
476
     * @var int        $params ['reply_to_message_id']
477
     * @var string     $params ['reply_markup']
478
     *
479
     * @return Message
480
     */
481 2
    public function sendVideo(array $params)
482
    {
483 2
        $params = $this->emojify($params, 'caption');
484
485 2
        return $this->uploadFile('sendVideo', $params);
486
    }
487
488
    /**
489
     * Send voice audio files.
490
     *
491
     * <code>
492
     * $params = [
493
     *   'chat_id'              => '',
494
     *   'voice'                => '',
495
     *   'duration'             => '',
496
     *   'disable_notification' => '',
497
     *   'reply_to_message_id'  => '',
498
     *   'reply_markup'         => '',
499
     * ];
500
     * </code>
501
     *
502
     * @link https://core.telegram.org/bots/api#sendaudio
503
     *
504
     * @param array    $params
505
     *
506
     * @var int|string $params ['chat_id']
507
     * @var string     $params ['voice']
508
     * @var int        $params ['duration']
509
     * @var bool       $params ['disable_notification']
510
     * @var int        $params ['reply_to_message_id']
511
     * @var string     $params ['reply_markup']
512
     *
513
     * @return Message
514
     */
515 2
    public function sendVoice(array $params)
516
    {
517 2
        return $this->uploadFile('sendVoice', $params);
518
    }
519
520
    /**
521
     * Send point on the map.
522
     *
523
     * <code>
524
     * $params = [
525
     *   'chat_id'              => '',
526
     *   'latitude'             => '',
527
     *   'longitude'            => '',
528
     *   'disable_notification' => '',
529
     *   'reply_to_message_id'  => '',
530
     *   'reply_markup'         => '',
531
     * ];
532
     * </code>
533
     *
534
     * @link https://core.telegram.org/bots/api#sendlocation
535
     *
536
     * @param array    $params
537
     *
538
     * @var int|string $params ['chat_id']
539
     * @var float      $params ['latitude']
540
     * @var float      $params ['longitude']
541
     * @var bool       $params ['disable_notification']
542
     * @var int        $params ['reply_to_message_id']
543
     * @var string     $params ['reply_markup']
544
     *
545
     * @return Message
546
     */
547 2
    public function sendLocation(array $params)
548
    {
549 2
        $response = $this->post('sendLocation', $params);
550
551 2
        return new Message($response->getDecodedBody());
552
    }
553
554
    /**
555
     * Send information about a venue.
556
     *
557
     * <code>
558
     * $params = [
559
     *   'chat_id'              => '',
560
     *   'latitude'             => '',
561
     *   'longitude'            => '',
562
     *   'title'                => '',
563
     *   'address'              => '',
564
     *   'foursquare_id'        => '',
565
     *   'disable_notification' => '',
566
     *   'reply_to_message_id'  => '',
567
     *   'reply_markup'         => '',
568
     * ];
569
     * </code>
570
     *
571
     * @link https://core.telegram.org/bots/api#sendvenue
572
     *
573
     * @param array    $params
574
     *
575
     * @var int|string $params ['chat_id']
576
     * @var float      $params ['latitude']
577
     * @var float      $params ['longitude']
578
     * @var string     $params ['title']
579
     * @var string     $params ['address']
580
     * @var string     $params ['foursquare_id']
581
     * @var bool       $params ['disable_notification']
582
     * @var int        $params ['reply_to_message_id']
583
     * @var string     $params ['reply_markup']
584
     *
585
     * @return Message
586
     */
587
    public function sendVenue(array $params)
588
    {
589
        $response = $this->post('sendVenue', $params);
590
591
        return new Message($response->getDecodedBody());
592
    }
593
594
    /**
595
     * Send phone contacts.
596
     *
597
     * <code>
598
     * $params = [
599
     *   'chat_id'              => '',
600
     *   'phone_number'         => '',
601
     *   'first_name'           => '',
602
     *   'last_name'            => '',
603
     *   'disable_notification' => '',
604
     *   'reply_to_message_id'  => '',
605
     *   'reply_markup'         => '',
606
     * ];
607
     * </code>
608
     *
609
     * @link https://core.telegram.org/bots/api#sendcontact
610
     *
611
     * @param array    $params
612
     *
613
     * @var int|string $params ['chat_id']
614
     * @var string     $params ['phone_number']
615
     * @var string     $params ['first_name']
616
     * @var string     $params ['last_name']
617
     * @var bool       $params ['disable_notification']
618
     * @var int        $params ['reply_to_message_id']
619
     * @var string     $params ['reply_markup']
620
     *
621
     * @return Message
622
     */
623
    public function sendContact(array $params)
624
    {
625
        $response = $this->post('sendContact', $params);
626
627
        return new Message($response->getDecodedBody());
628
    }
629
630
    /**
631
     * Broadcast a Chat Action.
632
     *
633
     * <code>
634
     * $params = [
635
     *   'chat_id' => '',
636
     *   'action'  => '',
637
     * ];
638
     * </code>
639
     *
640
     * @link https://core.telegram.org/bots/api#sendchataction
641
     *
642
     * @param array    $params
643
     *
644
     * @var int|string $params ['chat_id']
645
     * @var string     $params ['action']
646
     *
647
     * @throws TelegramSDKException
648
     *
649
     * @return TelegramResponse
650
     */
651 4
    public function sendChatAction(array $params)
652
    {
653
        $validActions = [
654 4
            'typing',
655 4
            'upload_photo',
656 4
            'record_video',
657 4
            'upload_video',
658 4
            'record_audio',
659 4
            'upload_audio',
660 4
            'upload_document',
661 4
            'find_location',
662 4
        ];
663
664 4
        if (isset($params['action']) && in_array($params['action'], $validActions)) {
665 2
            return $this->post('sendChatAction', $params);
666
        }
667
668 2
        throw new TelegramSDKException('Invalid Action! Accepted value: '.implode(', ', $validActions));
669
    }
670
671
    /**
672
     * Returns a list of profile pictures for a user.
673
     *
674
     * <code>
675
     * $params = [
676
     *   'user_id' => '',
677
     *   'offset'  => '',
678
     *   'limit'   => '',
679
     * ];
680
     * </code>
681
     *
682
     * @link https://core.telegram.org/bots/api#getuserprofilephotos
683
     *
684
     * @param array $params
685
     *
686
     * @var int     $params ['user_id']
687
     * @var int     $params ['offset']
688
     * @var int     $params ['limit']
689
     *
690
     * @return UserProfilePhotos
691
     */
692
    public function getUserProfilePhotos(array $params)
693
    {
694
        $response = $this->post('getUserProfilePhotos', $params);
695
696
        return new UserProfilePhotos($response->getDecodedBody());
697
    }
698
699
    /**
700
     * Returns basic info about a file and prepare it for downloading.
701
     *
702
     * <code>
703
     * $params = [
704
     *   'file_id' => '',
705
     * ];
706
     * </code>
707
     *
708
     * The file can then be downloaded via the link
709
     * https://api.telegram.org/file/bot<token>/<file_path>,
710
     * where <file_path> is taken from the response.
711
     *
712
     * @link https://core.telegram.org/bots/api#getFile
713
     *
714
     * @param array $params
715
     *
716
     * @var string  $params ['file_id']
717
     *
718
     * @return File
719
     */
720 2
    public function getFile(array $params)
721
    {
722 2
        $response = $this->post('getFile', $params);
723
724 2
        return new File($response->getDecodedBody());
725
    }
726
727
    /**
728
     * Kick a user from a group or a supergroup.
729
     *
730
     * In the case of supergroups, the user will not be able to return to the group on their own using
731
     * invite links etc., unless unbanned first.
732
     *
733
     * The bot must be an administrator in the group for this to work.
734
     *
735
     * <code>
736
     * $params = [
737
     *   'chat_id'              => '',
738
     *   'user_id'              => '',
739
     * ];
740
     * </code>
741
     *
742
     * @link https://core.telegram.org/bots/api#kickchatmember
743
     *
744
     * @param array    $params
745
     *
746
     * @var int|string $params ['chat_id']
747
     * @var int        $params ['user_id']
748
     *
749
     * @return TelegramResponse
750
     */
751
    public function kickChatMember(array $params)
752
    {
753
        return $this->post('kickChatMember', $params);
754
    }
755
756
    /**
757
     * Unban a previously kicked user in a supergroup.
758
     *
759
     * The user will not return to the group automatically, but will be able to join via link, etc.
760
     *
761
     * The bot must be an administrator in the group for this to work.
762
     *
763
     * <code>
764
     * $params = [
765
     *   'chat_id'              => '',
766
     *   'user_id'              => '',
767
     * ];
768
     * </code>
769
     *
770
     * @link https://core.telegram.org/bots/api#unbanchatmember
771
     *
772
     * @param array    $params
773
     *
774
     * @var int|string $params ['chat_id']
775
     * @var int        $params ['user_id']
776
     *
777
     * @return TelegramResponse
778
     */
779
    public function unbanChatMember(array $params)
780
    {
781
        return $this->post('unbanChatMember', $params);
782
    }
783
784
    /**
785
     * Send answers to callback queries sent from inline keyboards.
786
     *
787
     * he answer will be displayed to the user as a notification at the top of the chat screen or as an alert.
788
     *
789
     * <code>
790
     * $params = [
791
     *   'callback_query_id'  => '',
792
     *   'text'               => '',
793
     *   'show_alert'         => '',
794
     * ];
795
     * </code>
796
     *
797
     * @link https://core.telegram.org/bots/api#answerCallbackQuery
798
     *
799
     * @param array $params
800
     *
801
     * @var string  $params ['callback_query_id']
802
     * @var string  $params ['text']
803
     * @var bool    $params ['show_alert']
804
     *
805
     * @return TelegramResponse
806
     */
807
    public function answerCallbackQuery(array $params)
808
    {
809
        $params = $this->emojify($params, 'text');
810
811
        return $this->post('answerCallbackQuery', $params);
812
    }
813
814
    /**
815
     * Edit text messages sent by the bot or via the bot (for inline bots).
816
     *
817
     * <code>
818
     * $params = [
819
     *   'chat_id'                  => '',
820
     *   'message_id'               => '',
821
     *   'inline_message_id'        => '',
822
     *   'text'                     => '',
823
     *   'parse_mode'               => '',
824
     *   'disable_web_page_preview' => '',
825
     *   'reply_markup'             => '',
826
     * ];
827
     * </code>
828
     *
829
     * @link https://core.telegram.org/bots/api#editMessageText
830
     *
831
     * @param array    $params
832
     *
833
     * @var int|string $params ['chat_id']
834
     * @var int        $params ['message_id']
835
     * @var string     $params ['inline_message_id']
836
     * @var string     $params ['text']
837
     * @var string     $params ['parse_mode']
838
     * @var bool       $params ['disable_web_page_preview']
839
     * @var string     $params ['reply_markup']
840
     *
841
     * @return TelegramResponse
842
     */
843 View Code Duplication
    public function editMessageText(array $params)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
844
    {
845
        $params = $this->emojify($params, 'text');
846
        $response = $this->post('editMessageText', $params);
847
848
        return new Message($response->getDecodedBody());
849
    }
850
851
    /**
852
     * Edit captions of messages sent by the bot or via the bot (for inline bots).
853
     *
854
     * <code>
855
     * $params = [
856
     *   'chat_id'                  => '',
857
     *   'message_id'               => '',
858
     *   'inline_message_id'        => '',
859
     *   'caption'                  => '',
860
     *   'reply_markup'             => '',
861
     * ];
862
     * </code>
863
     *
864
     * @link https://core.telegram.org/bots/api#editMessageCaption
865
     *
866
     * @param array    $params
867
     *
868
     * @var int|string $params ['chat_id']
869
     * @var int        $params ['message_id']
870
     * @var string     $params ['inline_message_id']
871
     * @var string     $params ['caption']
872
     * @var string     $params ['reply_markup']
873
     *
874
     * @return TelegramResponse
875
     */
876
    public function editMessageCaption(array $params)
877
    {
878
        $params = $this->emojify($params, 'caption');
879
        $response = $this->post('editMessageCaption', $params);
880
881
        return new Message($response->getDecodedBody());
882
    }
883
884
    /**
885
     * Edit only the reply markup of messages sent by the bot or via the bot (for inline bots).
886
     *
887
     * <code>
888
     * $params = [
889
     *   'chat_id'                  => '',
890
     *   'message_id'               => '',
891
     *   'inline_message_id'        => '',
892
     *   'reply_markup'             => '',
893
     * ];
894
     * </code>
895
     *
896
     * @link https://core.telegram.org/bots/api#editMessageReplyMarkup
897
     *
898
     * @param array    $params
899
     *
900
     * @var int|string $params ['chat_id']
901
     * @var int        $params ['message_id']
902
     * @var string     $params ['inline_message_id']
903
     * @var string     $params ['reply_markup']
904
     *
905
     * @return TelegramResponse
906
     */
907
    public function editMessageReplyMarkup(array $params)
908
    {
909
        $response = $this->post('editMessageReplyMarkup', $params);
910
911
        return new Message($response->getDecodedBody());
912
    }
913
914
    /**
915
     * Use this method to send answers to an inline query.
916
     *
917
     * <code>
918
     * $params = [
919
     *   'inline_query_id'      => '',
920
     *   'results'              => [],
921
     *   'cache_time'           => 0,
922
     *   'is_personal'          => false,
923
     *   'next_offset'          => '',
924
     *   'switch_pm_text'       => '',
925
     *   'switch_pm_parameter'  => '',
926
     * ];
927
     * </code>
928
     *
929
     * @link https://core.telegram.org/bots/api#answerinlinequery
930
     *
931
     * @param array     $params
932
     *
933
     * @var string      $params ['inline_query_id']
934
     * @var array       $params ['results']
935
     * @var int|null    $params ['cache_time']
936
     * @var bool|null   $params ['is_personal']
937
     * @var string|null $params ['next_offset']
938
     * @var string|null $params ['switch_pm_text']
939
     * @var string|null $params ['switch_pm_parameter']
940
     *
941
     * @return bool
942
     */
943
    public function answerInlineQuery(array $params = [])
944
    {
945
        if (is_array($params['results'])) {
946
            $params['results'] = json_encode($params['results']);
947
        }
948
949
        return $this->post('answerInlineQuery', $params);
950
    }
951
952
    /**
953
     * Set a Webhook to receive incoming updates via an outgoing webhook.
954
     *
955
     * <code>
956
     * $params = [
957
     *   'url'         => '',
958
     *   'certificate' => '',
959
     * ];
960
     * </code>
961
     *
962
     * @link https://core.telegram.org/bots/api#setwebhook
963
     *
964
     * @param array $params
965
     *
966
     * @var string  $params ['url']         HTTPS url to send updates to.
967
     * @var string  $params ['certificate'] Upload your public key certificate so that the root certificate in
968
     *                                      use can be checked.
969
     *
970
     * @throws TelegramSDKException
971
     *
972
     * @return TelegramResponse
973
     */
974 6
    public function setWebhook(array $params)
975
    {
976 6
        if (filter_var($params['url'], FILTER_VALIDATE_URL) === false) {
977 2
            throw new TelegramSDKException('Invalid URL Provided');
978
        }
979
980 4
        if (parse_url($params['url'], PHP_URL_SCHEME) !== 'https') {
981 2
            throw new TelegramSDKException('Invalid URL, should be a HTTPS url.');
982
        }
983
984 2
        return $this->uploadFile('setWebhook', $params);
985
    }
986
987
    /**
988
     * Returns webhook updates sent by Telegram.
989
     * Works only if you set a webhook.
990
     *
991
     * @see setWebhook
992
     *
993
     * @return Update
994
     */
995
    public function getWebhookUpdates()
996
    {
997
        $body = json_decode(file_get_contents('php://input'), true);
998
999
        return new Update($body);
1000
    }
1001
1002
    /**
1003
     * Removes the outgoing webhook (if any).
1004
     *
1005
     * @return TelegramResponse
1006
     */
1007 2
    public function removeWebhook()
1008
    {
1009 2
        $url = '';
1010
1011 2
        return $this->post('setWebhook', compact('url'));
1012
    }
1013
1014
    /**
1015
     * Use this method to receive incoming updates using long polling.
1016
     *
1017
     * <code>
1018
     * $params = [
1019
     *   'offset'  => '',
1020
     *   'limit'   => '',
1021
     *   'timeout' => '',
1022
     * ];
1023
     * </code>
1024
     *
1025
     * @link https://core.telegram.org/bots/api#getupdates
1026
     *
1027
     * @param array  $params
1028
     *
1029
     * @var int|null $params ['offset']
1030
     * @var int|null $params ['limit']
1031
     * @var int|null $params ['timeout']
1032
     *
1033
     * @return Update[]
1034
     */
1035 6
    public function getUpdates(array $params = [])
1036
    {
1037 6
        $response = $this->post('getUpdates', $params);
1038 6
        $updates = $response->getDecodedBody();
1039
1040 6
        $data = [];
1041 6
        if (isset($updates['result'])) {
1042 6
            foreach ($updates['result'] as $update) {
1043
                /** @var Update $d */
1044
1045 6
                $messageIdUnique = true;
1046 6
                foreach ($data as $d) {
1047
                    // TODO investigate duplicate message_ids (they come with response)
1048
                    if ($d->getMessage()->getMessageId() === $update['message']['message_id']) {
1049
                        $messageIdUnique = false;
1050
                    }
1051 6
                }
1052
1053 6
                if ($messageIdUnique) {
1054 6
                    $data[] = new Update($update);
1055 6
                }
1056 6
            }
1057 6
        }
1058
1059 6
        return $data;
1060
    }
1061
1062
1063
    /**
1064
     * Builds a custom keyboard markup.
1065
     *
1066
     * <code>
1067
     * $params = [
1068
     *   'keyboard'          => '',
1069
     *   'resize_keyboard'   => '',
1070
     *   'one_time_keyboard' => '',
1071
     *   'selective'         => '',
1072
     * ];
1073
     * </code>
1074
     *
1075
     * @deprecated Use Telegram\Bot\Keyboard\Keyboard::make(array $params = []) instead.
1076
     *             To be removed in next major version.
1077
     *
1078
     * @link       https://core.telegram.org/bots/api#replykeyboardmarkup
1079
     *
1080
     * @param array $params
1081
     *
1082
     * @var array   $params ['keyboard']
1083
     * @var bool    $params ['resize_keyboard']
1084
     * @var bool    $params ['one_time_keyboard']
1085
     * @var bool    $params ['selective']
1086
     *
1087
     * @return string
1088
     */
1089
    public function replyKeyboardMarkup(array $params)
1090
    {
1091
        return Keyboard::make($params);
1092
    }
1093
1094
    /**
1095
     * Hide the current custom keyboard and display the default letter-keyboard.
1096
     *
1097
     * <code>
1098
     * $params = [
1099
     *   'hide_keyboard' => true,
1100
     *   'selective'     => false,
1101
     * ];
1102
     * </code>
1103
     *
1104
     * @deprecated Use Telegram\Bot\Keyboard\Keyboard::hide(array $params = []) instead.
1105
     *             To be removed in next major version.
1106
     *
1107
     * @link       https://core.telegram.org/bots/api#replykeyboardhide
1108
     *
1109
     * @param array $params
1110
     *
1111
     * @var bool    $params ['hide_keyboard']
1112
     * @var bool    $params ['selective']
1113
     *
1114
     * @return string
1115
     */
1116
    public static function replyKeyboardHide(array $params = [])
1117
    {
1118
        return Keyboard::hide($params);
1119
    }
1120
1121
    /**
1122
     * Display a reply interface to the user (act as if the user has selected the bot‘s message and tapped ’Reply').
1123
     *
1124
     * <code>
1125
     * $params = [
1126
     *   'force_reply' => true,
1127
     *   'selective'   => false,
1128
     * ];
1129
     * </code>
1130
     *
1131
     * @deprecated Use Telegram\Bot\Keyboard\Keyboard::forceReply(array $params = []) instead.
1132
     *             To be removed in next major version.
1133
     *
1134
     * @link       https://core.telegram.org/bots/api#forcereply
1135
     *
1136
     * @param array $params
1137
     *
1138
     * @var bool    $params ['force_reply']
1139
     * @var bool    $params ['selective']
1140
     *
1141
     * @return string
1142
     */
1143
    public static function forceReply(array $params = [])
1144
    {
1145
        return Keyboard::forceReply($params);
1146
    }
1147
1148
    /**
1149
     * Processes Inbound Commands.
1150
     *
1151
     * @param bool $webhook
1152
     *
1153
     * @return Update|Update[]
1154
     */
1155 6 View Code Duplication
    public function commandsHandler($webhook = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1156
    {
1157 6
        if ($webhook) {
1158
            $update = $this->getWebhookUpdates();
1159
            $this->processCommand($update);
1160
1161
            return $update;
1162
        }
1163
1164 6
        $updates = $this->getUpdates();
1165 6
        $highestId = -1;
1166
1167 6
        foreach ($updates as $update) {
1168 6
            $highestId = $update->getUpdateId();
1169 6
            $this->processCommand($update);
1170 6
        }
1171
1172
        //An update is considered confirmed as soon as getUpdates is called with an offset higher than its update_id.
1173 6
        if ($highestId != -1) {
1174 6
            $params = [];
1175 6
            $params['offset'] = $highestId + 1;
1176 6
            $params['limit'] = 1;
1177 6
            $this->getUpdates($params);
1178 6
        }
1179
1180 6
        return $updates;
1181
    }
1182
1183
1184
    /**
1185
     * Processes Inbound Conversations.
1186
     *
1187
     * @param bool $webhook
1188
     *
1189
     * @return Update|Update[]
1190
     */
1191 View Code Duplication
    public function conversationsHandler($webhook = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1192
    {
1193
        if ($webhook) {
1194
            $update = $this->getWebhookUpdates();
1195
            $this->processConversation($update);
1196
1197
            return $update;
1198
        }
1199
1200
        $updates = $this->getUpdates();
1201
        $highestId = -1;
1202
1203
        foreach ($updates as $update) {
1204
            $highestId = $update->getUpdateId();
1205
            $this->processConversation($update);
1206
        }
1207
1208
        //An update is considered confirmed as soon as getUpdates is called with an offset higher than its update_id.
1209
        if ($highestId != -1) {
1210
            $params = [];
1211
            $params['offset'] = $highestId + 1;
1212
            $params['limit'] = 1;
1213
            $this->getUpdates($params);
1214
        }
1215
1216
        return $updates;
1217
    }
1218
    
1219
    
1220
1221
    /**
1222
     * Check update object for a command and process.
1223
     *
1224
     * @param Update $update
1225
     */
1226 6 View Code Duplication
    public function processCommand(Update $update)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1227
    {
1228 6
        $message = $update->getMessage();
1229
1230 6
        if ($message !== null && $message->has('text')) {
1231 6
            $this->getCommandBus()->handler($message->getText(), $update);
1232 6
        }
1233 6
    }
1234
1235
    /**
1236
     * Check update object for a command and process.
1237
     *
1238
     * @param Update $update
1239
     */
1240 View Code Duplication
    public function processConversation(Update $update)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1241
    {
1242
        $message = $update->getMessage();
1243
1244
        if ($message !== null && $message->has('text')) {
1245
            $this->getConversationBus()->handler($message->getText(), $update);
1246
        }
1247
    }
1248
1249
    /**
1250
     * Helper to Trigger Commands.
1251
     *
1252
     * @param string $name   Command Name
1253
     * @param Update $update Update Object
1254
     *
1255
     * @return mixed
1256
     */
1257
    public function triggerCommand($name, Update $update)
1258
    {
1259
        return $this->getCommandBus()->execute($name, $update->getMessage()->getText(), $update);
1260
    }
1261
1262
    /**
1263
     * Determine if a given type is the message.
1264
     *
1265
     * @param string         $type
1266
     * @param Update|Message $object
1267
     *
1268
     * @return bool
1269
     */
1270
    public function isMessageType($type, $object)
1271
    {
1272
        if ($object instanceof Update) {
1273
            $object = $object->getMessage();
1274
        }
1275
1276
        if ($object->has(strtolower($type))) {
1277
            return true;
1278
        }
1279
1280
        return $this->detectMessageType($object) === $type;
1281
    }
1282
1283
    /**
1284
     * Detect Message Type Based on Update or Message Object.
1285
     *
1286
     * @param Update|Message $object
1287
     *
1288
     * @return string|null
1289
     */
1290
    public function detectMessageType($object)
1291
    {
1292
        if ($object instanceof Update) {
1293
            $object = $object->getMessage();
1294
        }
1295
1296
        $types = [
1297
            'text',
1298
            'audio',
1299
            'document',
1300
            'photo',
1301
            'sticker',
1302
            'video',
1303
            'voice',
1304
            'contact',
1305
            'location',
1306
            'venue',
1307
            'new_chat_member',
1308
            'left_chat_member',
1309
            'new_chat_title',
1310
            'new_chat_photo',
1311
            'delete_chat_photo',
1312
            'group_chat_created',
1313
            'supergroup_chat_created',
1314
            'channel_chat_created',
1315
            'migrate_to_chat_id',
1316
            'migrate_from_chat_id',
1317
            'pinned_message',
1318
        ];
1319
1320
        return $object->keys()
1321
            ->intersect($types)
1322
            ->pop();
1323
    }
1324
1325
    /**
1326
     * Sends a GET request to Telegram Bot API and returns the result.
1327
     *
1328
     * @param string $endpoint
1329
     * @param array  $params
1330
     *
1331
     * @throws TelegramSDKException
1332
     *
1333
     * @return TelegramResponse
1334
     */
1335
    protected function get($endpoint, $params = [])
1336
    {
1337
        if (array_key_exists('reply_markup', $params)) {
1338
            $params['reply_markup'] = (string)$params['reply_markup'];
1339
        }
1340
1341
        return $this->sendRequest(
1342
            'GET',
1343
            $endpoint,
1344
            $params
1345
        );
1346
    }
1347
1348
    /**
1349
     * Sends a POST request to Telegram Bot API and returns the result.
1350
     *
1351
     * @param string $endpoint
1352
     * @param array  $params
1353
     * @param bool   $fileUpload Set true if a file is being uploaded.
1354
     *
1355
     * @return TelegramResponse
1356
     */
1357 40
    protected function post($endpoint, array $params = [], $fileUpload = false)
1358
    {
1359 40
        if ($fileUpload) {
1360 16
            $params = ['multipart' => $params];
1361 16
        } else {
1362
1363 24
            if (array_key_exists('reply_markup', $params)) {
1364
                $params['reply_markup'] = (string)$params['reply_markup'];
1365
            }
1366
1367 24
            $params = ['form_params' => $params];
1368
        }
1369
1370 40
        return $this->sendRequest(
1371 40
            'POST',
1372 40
            $endpoint,
1373
            $params
1374 40
        );
1375
    }
1376
1377
    /**
1378
     * Sends a multipart/form-data request to Telegram Bot API and returns the result.
1379
     * Used primarily for file uploads.
1380
     *
1381
     * @param string $endpoint
1382
     * @param array  $params
1383
     *
1384
     * @throws TelegramSDKException
1385
     *
1386
     * @return Message
1387
     */
1388 16
    protected function uploadFile($endpoint, array $params = [])
1389
    {
1390 16
        $i = 0;
1391 16
        $multipart_params = [];
1392 16
        foreach ($params as $name => $contents) {
1393 16
            if (is_null($contents)) {
1394
                continue;
1395
            }
1396
1397 16
            if (!is_resource($contents) && $name !== 'url') {
1398 14
                $validUrl = filter_var($contents, FILTER_VALIDATE_URL);
1399 14
                $contents = (is_file($contents) || $validUrl) ? (new InputFile($contents))->open() : (string)$contents;
1400 14
            }
1401
1402 16
            $multipart_params[$i]['name'] = $name;
1403 16
            $multipart_params[$i]['contents'] = $contents;
1404 16
            ++$i;
1405 16
        }
1406
1407 16
        $response = $this->post($endpoint, $multipart_params, true);
1408
1409 16
        return new Message($response->getDecodedBody());
1410
    }
1411
1412
    /**
1413
     * Sends a request to Telegram Bot API and returns the result.
1414
     *
1415
     * @param string $method
1416
     * @param string $endpoint
1417
     * @param array  $params
1418
     *
1419
     * @throws TelegramSDKException
1420
     *
1421
     * @return TelegramResponse
1422
     */
1423 40
    protected function sendRequest(
1424
        $method,
1425
        $endpoint,
1426
        array $params = []
1427
    ) {
1428 40
        $request = $this->request($method, $endpoint, $params);
1429
1430 40
        return $this->lastResponse = $this->client->sendRequest($request);
1431
    }
1432
1433
    /**
1434
     * Instantiates a new TelegramRequest entity.
1435
     *
1436
     * @param string $method
1437
     * @param string $endpoint
1438
     * @param array  $params
1439
     *
1440
     * @return TelegramRequest
1441
     */
1442 40
    protected function request(
1443
        $method,
1444
        $endpoint,
1445
        array $params = []
1446
    ) {
1447 40
        return new TelegramRequest(
1448 40
            $this->getAccessToken(),
1449 40
            $method,
1450 40
            $endpoint,
1451 40
            $params,
1452 40
            $this->isAsyncRequest(),
1453 40
            $this->getTimeOut(),
1454 40
            $this->getConnectTimeOut()
1455 40
        );
1456
    }
1457
1458
    /**
1459
     * Magic method to process any "get" requests.
1460
     *
1461
     * @param $method
1462
     * @param $arguments
1463
     *
1464
     * @return bool|TelegramResponse|UnknownObject
1465
     */
1466 2
    public function __call($method, $arguments)
1467
    {
1468 2
        if (preg_match('/^\w+Commands?/', $method, $matches)) {
1469 2
            return call_user_func_array([$this->getCommandBus(), $matches[0]], $arguments);
1470
        }
1471
1472
        $action = substr($method, 0, 3);
1473
        if ($action === 'get') {
1474
            /* @noinspection PhpUndefinedFunctionInspection */
1475
            $class_name = studly_case(substr($method, 3));
1476
            $class = 'Telegram\Bot\Objects\\'.$class_name;
1477
            $response = $this->post($method, $arguments[0] ?: []);
1478
1479
            if (class_exists($class)) {
1480
                return new $class($response->getDecodedBody());
1481
            }
1482
1483
            return $response;
1484
        }
1485
        $response = $this->post($method, $arguments[0]);
1486
1487
        return new UnknownObject($response->getDecodedBody());
1488
    }
1489
1490
    /**
1491
     * Set the IoC Container.
1492
     *
1493
     * @param $container Container instance
1494
     *
1495
     * @return void
1496
     */
1497 2
    public static function setContainer(Container $container)
1498
    {
1499 2
        self::$container = $container;
1500 2
    }
1501
1502
    /**
1503
     * Get the IoC Container.
1504
     *
1505
     * @return Container
1506
     */
1507 2
    public function getContainer()
1508
    {
1509 2
        return self::$container;
1510
    }
1511
1512
    /**
1513
     * Check if IoC Container has been set.
1514
     *
1515
     * @return boolean
1516
     */
1517
    public function hasContainer()
1518
    {
1519
        return self::$container !== null;
1520
    }
1521
1522
    /**
1523
     * @return int
1524
     */
1525 40
    public function getTimeOut()
1526
    {
1527 40
        return $this->timeOut;
1528
    }
1529
1530
    /**
1531
     * @param int $timeOut
1532
     *
1533
     * @return $this
1534
     */
1535 2
    public function setTimeOut($timeOut)
1536
    {
1537 2
        $this->timeOut = $timeOut;
1538
1539 2
        return $this;
1540
    }
1541
1542
    /**
1543
     * @return int
1544
     */
1545 40
    public function getConnectTimeOut()
1546
    {
1547 40
        return $this->connectTimeOut;
1548
    }
1549
1550
    /**
1551
     * @param int $connectTimeOut
1552
     *
1553
     * @return $this
1554
     */
1555 2
    public function setConnectTimeOut($connectTimeOut)
1556
    {
1557 2
        $this->connectTimeOut = $connectTimeOut;
1558
1559 2
        return $this;
1560
    }
1561
1562
    /**
1563
     * Emojify Given Property in Params.
1564
     *
1565
     * @param array  $params
1566
     * @param string $property
1567
     *
1568
     * @return mixed
1569
     */
1570 12
    protected function emojify(array $params, $property)
1571
    {
1572 12
        if (!$this->isUseEmojify()) {
1573
            return $params;
1574
        }
1575 12
        if (isset($params[$property])) {
1576 4
            $params[$property] = Emojify::text($params[$property]);
1577 4
        }
1578
1579 12
        return $params;
1580
    }
1581
1582
    /**
1583
     * Change the behavior of using Emojify.
1584
     *
1585
     * @param bool $useEmojify
1586
     *
1587
     * @return Api
1588
     */
1589 2
    public function setUseEmojify($useEmojify)
1590
    {
1591 2
        $this->useEmojify = $useEmojify;
1592
1593 2
        return $this;
1594
    }
1595
1596
    /**
1597
     * Check if Emojify is enabled.
1598
     *
1599
     * @return bool
1600
     */
1601 14
    public function isUseEmojify()
1602
    {
1603 14
        return $this->useEmojify;
1604
    }
1605
}
1606