Completed
Push — develop ( 3da8ea...4ed2e0 )
by Michele
31:51 queued 14:02
created

TelegramTrait::editMessageText()   B

Complexity

Conditions 9
Paths 9

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 9
eloc 12
c 2
b 0
f 0
nc 9
nop 2
dl 0
loc 21
rs 8.0555
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Zanzara\Telegram;
6
7
use Clue\React\Buzz\Browser;
8
use Clue\React\Buzz\Message\ResponseException;
9
use Psr\Container\ContainerInterface;
10
use Psr\Http\Message\ResponseInterface;
11
use React\Filesystem\Filesystem;
12
use React\Promise\PromiseInterface;
13
use RingCentral\Psr7\MultipartStream;
14
use Zanzara\Config;
15
use Zanzara\MessageQueue;
16
use Zanzara\Telegram\Type\CallbackQuery;
17
use Zanzara\Telegram\Type\Chat;
18
use Zanzara\Telegram\Type\ChatMember;
19
use Zanzara\Telegram\Type\File\File;
20
use Zanzara\Telegram\Type\File\StickerSet;
21
use Zanzara\Telegram\Type\File\UserProfilePhotos;
22
use Zanzara\Telegram\Type\Game\GameHighScore;
23
use Zanzara\Telegram\Type\Input\InputFile;
24
use Zanzara\Telegram\Type\Message;
25
use Zanzara\Telegram\Type\Poll\Poll;
26
use Zanzara\Telegram\Type\Response\TelegramException;
27
use Zanzara\Telegram\Type\Update;
28
use Zanzara\Telegram\Type\Webhook\WebhookInfo;
29
use Zanzara\ZanzaraLogger;
30
use Zanzara\ZanzaraMapper;
31
use function React\Promise\all;
32
33
/**
34
 * Class that interacts with Telegram Api.
35
 * Made trait in order to be used both by Telegram and Context classes.
36
 *
37
 * @see Telegram
38
 * @see Context
39
 */
40
trait TelegramTrait
41
{
42
43
    /**
44
     * @var ContainerInterface
45
     */
46
    protected $container;
47
48
    /**
49
     * @var Browser
50
     */
51
    protected $browser;
52
53
    /**
54
     * @var Update
55
     */
56
    protected $update;
57
58
    /**
59
     * Use this method to receive incoming updates using long polling (wiki). An Array of @see Update objects is returned.
60
     *
61
     * More on https://core.telegram.org/bots/api#getupdates
62
     *
63
     * @param array $opt
64
     * @return PromiseInterface
65
     */
66
    public function getUpdates(array $opt = []): PromiseInterface
67
    {
68
        $method = "getUpdates";
69
        $query = http_build_query($opt);
70
71
        $browser = $this->browser->withOptions(array(
72
            "timeout" => $opt['timeout'] + 10 //timout browser necessary bigger than telegram timeout. They can't be equal
73
        ));
74
75
        return $this->wrapPromise($browser->get("$method?$query"), $method, $opt, Update::class);
76
    }
77
78
    /**
79
     * Use this method to send text messages. On success, the sent @see Message is returned.
80
     *
81
     * By default the message is sent to the chat_id of the context's update. Use $opt param to specify a different
82
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
83
     *
84
     * More on https://core.telegram.org/bots/api#sendmessage
85
     *
86
     * @param string $text
87
     * @param array|null $opt = [
88
     *     'chat_id' => 123456789,
89
     *     'parse_mode' => 'HTML',
90
     *     'disable_web_page_preview' => true,
91
     *     'disable_notification' => true,
92
     *     'reply_to_message_id' => 123456789,
93
     *     'reply_markup' => ['force_reply' => true],
94
     *     'reply_markup' => ['inline_keyboard' => [[
95
     *          ['callback_data' => 'data', 'text' => 'text']
96
     *      ]]],
97
     *      'reply_markup' => ['resize_keyboard' => true, 'one_time_keyboard' => true, 'selective' => true, 'keyboard' => [[
98
     *          ['text' => 'text', 'request_contact' => true, 'request_location' => true, 'request_poll' => ['type' => 'quiz']]
99
     *      ]]]
100
     * ]
101
     * @return PromiseInterface
102
     */
103
    public function sendMessage(string $text, ?array $opt = [])
104
    {
105
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
106
        $required = compact("text");
107
        $params = array_merge($required, $opt);
108
        return $this->doSendMessage($params);
109
    }
110
111
    /**
112
     * Do not use it. Use @see TelegramTrait::sendMessage() instead.
113
     *
114
     * @internal
115
     * @param array $params
116
     * @return PromiseInterface
117
     */
118
    public function doSendMessage(array $params): PromiseInterface
119
    {
120
        return $this->callApi("sendMessage", $params, Message::class);
121
    }
122
123
    /**
124
     * Use this method to send a message to many chats. This method takes care of sending the message
125
     * with a delay in order avoid 429 Telegram errors (https://core.telegram.org/bots/faq#broadcasting-to-users).
126
     *
127
     * Eg. $ctx->sendBulkMessage([1111111111, 2222222222, 333333333], 'A wonderful notification', [parse_mode => 'HTML']);
128
     *
129
     * More on https://core.telegram.org/bots/api#sendmessage
130
     *
131
     * @param array $chatIds
132
     * @param string $text
133
     * @param array $opt
134
     */
135
    public function sendBulkMessage(array $chatIds, string $text, array $opt = []): void
136
    {
137
        $this->container->get(MessageQueue::class)
138
            ->push($chatIds, $text, $opt);
139
    }
140
141
    /**
142
     * Use this method to specify a url and receive incoming updates via an outgoing webhook. Whenever there is an update
143
     * for the bot, we will send an HTTPS POST request to the specified url, containing a JSON-serialized Update. In case
144
     * of an unsuccessful request, we will give up after a reasonable amount of attempts. Returns True on success.
145
     *
146
     * More on https://core.telegram.org/bots/api#setwebhook
147
     *
148
     * @param string $url
149
     * @param array|null $opt
150
     * @return PromiseInterface
151
     */
152
    public function setWebhook(string $url, ?array $opt = []): PromiseInterface
153
    {
154
        $required = compact("url");
155
        $params = array_merge($required, $opt);
156
        return $this->callApi("setWebhook", $params);
157
    }
158
159
    /**
160
     * Use this method to get current webhook status. Requires no parameters. On success, returns a @see WebhookInfo object.
161
     * If the bot is using getUpdates, will return an object with the url field empty.
162
     *
163
     * More on https://core.telegram.org/bots/api#getwebhookinfo
164
     *
165
     * @return PromiseInterface
166
     */
167
    public function getWebhookInfo(): PromiseInterface
168
    {
169
        return $this->callApi("getWebhookInfo", [], WebhookInfo::class);
170
    }
171
172
    /**
173
     * Use this method to remove webhook integration if you decide to switch back to getUpdates. Returns True on
174
     * success. Requires no parameters.
175
     *
176
     * More on https://core.telegram.org/bots/api#deletewebhook
177
     *
178
     * @return PromiseInterface
179
     */
180
    public function deleteWebhook(): PromiseInterface
181
    {
182
        return $this->callApi("deleteWebhook");
183
    }
184
185
    /**
186
     * Use this method to forward messages of any kind. On success, the sent @see Message is returned.
187
     *
188
     * More on https://core.telegram.org/bots/api#forwardmessage
189
     *
190
     * @param int $chat_id
191
     * @param int $from_chat_id
192
     * @param int $message_id
193
     * @param array|null $opt
194
     * @return PromiseInterface
195
     */
196
    public function forwardMessage(int $chat_id, int $from_chat_id, int $message_id, ?array $opt = []): PromiseInterface
197
    {
198
        $required = compact("chat_id", "from_chat_id", "message_id");
199
        $params = array_merge($required, $opt);
200
        return $this->callApi("forwardMessage", $params, Message::class);
201
    }
202
203
    /**
204
     * Use this method to send photos. On success, the sent @see Message is returned.
205
     *
206
     * The photo param can be either a string or a @see InputFile. Note that if you use the latter the file reading
207
     * operation is synchronous, so the main thread is blocked.
208
     * To make it asynchronous see https://github.com/badfarm/zanzara/wiki#working-with-files.
209
     *
210
     * By default the photo is sent to the chat_id of the context's update. Use $opt param to specify a different
211
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
212
     *
213
     * More on https://core.telegram.org/bots/api#sendphoto
214
     *
215
     * @param $photo
216
     * @param array|null $opt
217
     * @return PromiseInterface
218
     */
219
    public function sendPhoto($photo, ?array $opt = []): PromiseInterface
220
    {
221
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
222
        $required = compact("photo");
223
        $params = array_merge($required, $opt);
224
        return $this->callApi("sendPhoto", $params, Message::class);
225
    }
226
227
    /**
228
     * Use this method to send audio files, if you want Telegram clients to display them in the music player. Your audio
229
     * must be in the .MP3 or .M4A format. On success, the sent @see Message is returned. Bots can currently send audio files
230
     * of up to 50 MB in size, this limit may be changed in the future.
231
     *
232
     * The audio and thumb params can be either a string or a @see InputFile. Note that if you use the latter the file reading
233
     * operation is synchronous, so the main thread is blocked.
234
     * To make it asynchronous see https://github.com/badfarm/zanzara/wiki#working-with-files.
235
     *
236
     * By default the audio is sent to the chat_id of the context's update. Use $opt param to specify a different
237
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
238
     *
239
     * More on https://core.telegram.org/bots/api#sendaudio
240
     *
241
     * @param $audio
242
     * @param array|null $opt
243
     * @return PromiseInterface
244
     */
245
    public function sendAudio($audio, ?array $opt = []): PromiseInterface
246
    {
247
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
248
        $required = compact("audio");
249
        $params = array_merge($required, $opt);
250
        return $this->callApi("sendAudio", $params, Message::class);
251
    }
252
253
    /**
254
     * Use this method to send general files. On success, the sent @see Message is returned. Bots can currently send files of any
255
     * type of up to 50 MB in size, this limit may be changed in the future.
256
     *
257
     * The document and thumb params can be either a string or a @see InputFile. Note that if you use the latter the file reading
258
     * operation is synchronous, so the main thread is blocked.
259
     * To make it asynchronous see https://github.com/badfarm/zanzara/wiki#working-with-files.
260
     *
261
     * By default the document is sent to the chat_id of the context's update. Use $opt param to specify a different
262
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
263
     *
264
     * More on https://core.telegram.org/bots/api#senddocument
265
     *
266
     * @param $document
267
     * @param array|null $opt
268
     * @return PromiseInterface
269
     */
270
    public function sendDocument($document, ?array $opt = []): PromiseInterface
271
    {
272
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
273
        $required = compact("document");
274
        $params = array_merge($required, $opt);
275
        return $this->callApi("sendDocument", $params, Message::class);
276
    }
277
278
    /**
279
     * Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as Document). On
280
     * success, the sent @see Message is returned. Bots can currently send video files of up to 50 MB in size, this limit may
281
     * be changed in the future.
282
     *
283
     * The video and thumb params can be either a string or a @see InputFile. Note that if you use the latter the file reading
284
     * operation is synchronous, so the main thread is blocked.
285
     * To make it asynchronous see https://github.com/badfarm/zanzara/wiki#working-with-files.
286
     *
287
     * By default the video is sent to the chat_id of the context's update. Use $opt param to specify a different
288
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
289
     *
290
     * More on https://core.telegram.org/bots/api#sendvideo
291
     *
292
     * @param $video
293
     * @param array|null $opt
294
     * @return PromiseInterface
295
     */
296
    public function sendVideo($video, ?array $opt = []): PromiseInterface
297
    {
298
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
299
        $required = compact("video");
300
        $params = array_merge($required, $opt);
301
        return $this->callApi("sendVideo", $params, Message::class);
302
    }
303
304
    /**
305
     * Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). On success, the sent @see Message
306
     * is returned. Bots can currently send animation files of up to 50 MB in size, this limit may be changed in the
307
     * future.
308
     *
309
     * The animation and thumb params can be either a string or a @see InputFile. Note that if you use the latter the file reading
310
     * operation is synchronous, so the main thread is blocked.
311
     * To make it asynchronous see https://github.com/badfarm/zanzara/wiki#working-with-files.
312
     *
313
     * By default the animation is sent to the chat_id of the context's update. Use $opt param to specify a different
314
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
315
     *
316
     * More on https://core.telegram.org/bots/api#sendanimation
317
     *
318
     * @param $animation
319
     * @param array|null $opt
320
     * @return PromiseInterface
321
     */
322
    public function sendAnimation($animation, ?array $opt = []): PromiseInterface
323
    {
324
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
325
        $required = compact("animation");
326
        $params = array_merge($required, $opt);
327
        return $this->callApi("sendAnimation", $params, Message::class);
328
    }
329
330
    /**
331
     * Use this method to send audio files, if you want Telegram clients to display the file as a playable voice message.
332
     * For this to work, your audio must be in an .OGG file encoded with OPUS (other formats may be sent as Audio or
333
     * Document). On success, the sent @see Message is returned. Bots can currently send voice messages of up to 50 MB in
334
     * size, this limit may be changed in the future.
335
     *
336
     * The voice param can be either a string or a @see InputFile. Note that if you use the latter the file reading
337
     * operation is synchronous, so the main thread is blocked.
338
     * To make it asynchronous see https://github.com/badfarm/zanzara/wiki#working-with-files.
339
     *
340
     * By default the voice is sent to the chat_id of the context's update. Use $opt param to specify a different
341
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
342
     *
343
     * More on https://core.telegram.org/bots/api#sendvoice
344
     *
345
     * @param $voice
346
     * @param array|null $opt
347
     * @return PromiseInterface
348
     */
349
    public function sendVoice($voice, ?array $opt = []): PromiseInterface
350
    {
351
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
352
        $required = compact("voice");
353
        $params = array_merge($required, $opt);
354
        return $this->callApi("sendVoice", $params, Message::class);
355
    }
356
357
    /**
358
     * As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute long. Use this method to send video
359
     * messages. On success, the sent @see Message is returned.
360
     *
361
     * The video_note and thumb params can be either a string or a @see InputFile. Note that if you use the latter the file reading
362
     * operation is synchronous, so the main thread is blocked.
363
     * To make it asynchronous see https://github.com/badfarm/zanzara/wiki#working-with-files.
364
     *
365
     * By default the video note is sent to the chat_id of the context's update. Use $opt param to specify a different
366
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
367
     *
368
     * More on https://core.telegram.org/bots/api#sendvideonote
369
     *
370
     * @param $video_note
371
     * @param array|null $opt
372
     * @return PromiseInterface
373
     */
374
    public function sendVideoNote($video_note, ?array $opt = []): PromiseInterface
375
    {
376
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
377
        $required = compact("video_note");
378
        $params = array_merge($required, $opt);
379
        return $this->callApi("sendVideoNote", $params, Message::class);
380
    }
381
382
    /**
383
     * Use this method to send a group of photos or videos as an album. On success, an array of the sent @see Message 's is returned.
384
     *
385
     * By default the media group is sent to the chat_id of the context's update. Use $opt param to specify a different
386
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
387
     *
388
     * More on https://core.telegram.org/bots/api#sendmediagroup
389
     *
390
     * @param $media
391
     * @param array|null $opt
392
     * @return PromiseInterface
393
     */
394
    public function sendMediaGroup($media, ?array $opt = []): PromiseInterface
395
    {
396
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
397
        $required = compact("media");
398
        $params = array_merge($required, $opt);
399
        return $this->callApi("sendMediaGroup", $params, Message::class);
400
    }
401
402
    /**
403
     * Use this method to send point on the map. On success, the sent @see Message is returned.
404
     *
405
     * By default the location is sent to the chat_id of the context's update. Use $opt param to specify a different
406
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
407
     *
408
     * More on https://core.telegram.org/bots/api#sendlocation
409
     *
410
     * @param $latitude
411
     * @param $longitude
412
     * @param array|null $opt
413
     * @return PromiseInterface
414
     */
415
    public function sendLocation($latitude, $longitude, ?array $opt = []): PromiseInterface
416
    {
417
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
418
        $required = compact("latitude", "longitude");
419
        $params = array_merge($required, $opt);
420
        return $this->callApi("sendLocation", $params, Message::class);
421
    }
422
423
    /**
424
     * Use this method to edit live location messages. A location can be edited until its live_period expires or editing is
425
     * explicitly disabled by a call to stopMessageLiveLocation. On success, if the edited message was sent by the bot,
426
     * the edited @see Message is returned, otherwise True is returned.
427
     *
428
     * More on https://core.telegram.org/bots/api#editmessagelivelocation
429
     *
430
     * @param $latitude
431
     * @param $longitude
432
     * @param array|null $opt
433
     * @return PromiseInterface
434
     */
435
    public function editMessageLiveLocation($latitude, $longitude, ?array $opt = []): PromiseInterface
436
    {
437
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
438
        $required = compact("latitude", "longitude");
439
        $params = array_merge($required, $opt);
440
        return $this->callApi("editMessageLiveLocation", $params, Message::class);
441
    }
442
443
    /**
444
     * Use this method to stop updating a live location message before live_period expires. On success, if the message was
445
     * sent by the bot, the sent @see Message is returned, otherwise True is returned.
446
     *
447
     * More on https://core.telegram.org/bots/api#stopmessagelivelocation
448
     *
449
     * @param array|null $opt
450
     * @return PromiseInterface
451
     */
452
    public function stopMessageLiveLocation(?array $opt = []): PromiseInterface
453
    {
454
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
455
        return $this->callApi("stopMessageLiveLocation", $opt, Message::class);
456
    }
457
458
    /**
459
     * Use this method to send information about a venue. On success, the sent @see Message is returned.
460
     *
461
     * By default the venue is sent to the chat_id of the context's update. Use $opt param to specify a different
462
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
463
     *
464
     * More on https://core.telegram.org/bots/api#sendvenue
465
     *
466
     * @param $latitude
467
     * @param $longitude
468
     * @param string $title
469
     * @param string $address
470
     * @param array|null $opt
471
     * @return PromiseInterface
472
     */
473
    public function sendVenue($latitude, $longitude, string $title, string $address, ?array $opt = []): PromiseInterface
474
    {
475
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
476
        $required = compact("latitude", "longitude", "title", "address");
477
        $params = array_merge($required, $opt);
478
        return $this->callApi("sendVenue", $params, Message::class);
479
    }
480
481
    /**
482
     * Use this method to send phone contacts. On success, the sent @see Message is returned.
483
     *
484
     * By default the contact is sent to the chat_id of the context's update. Use $opt param to specify a different
485
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
486
     *
487
     * More on https://core.telegram.org/bots/api#sendcontact
488
     *
489
     * @param string $phone_number
490
     * @param string $first_name
491
     * @param array|null $opt
492
     * @return PromiseInterface
493
     */
494
    public function sendContact(string $phone_number, string $first_name, ?array $opt = []): PromiseInterface
495
    {
496
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
497
        $required = compact("phone_number", "first_name");
498
        $params = array_merge($required, $opt);
499
        return $this->callApi("sendContact", $params, Message::class);
500
    }
501
502
    /**
503
     * Use this method to send a native poll. On success, the sent @see Message is returned.
504
     *
505
     * By default the poll is sent to the chat_id of the context's update. Use $opt param to specify a different
506
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
507
     *
508
     * More on https://core.telegram.org/bots/api#sendpoll
509
     *
510
     * @param string $question
511
     * @param $options
512
     * @param array|null $opt
513
     * @return PromiseInterface
514
     */
515
    public function sendPoll(string $question, $options, ?array $opt = []): PromiseInterface
516
    {
517
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
518
        $required = compact("question", "options");
519
        $params = array_merge($required, $opt);
520
        return $this->callApi("sendPoll", $params, Message::class);
521
    }
522
523
    /**
524
     * Use this method to send a dice, which will have a random value from 1 to 6. On success, the sent @see Message is returned.
525
     * (Yes, we're aware of the "proper" singular of die. But it's awkward, and we decided to help it change. One dice at
526
     * a time!)
527
     *
528
     * By default the dice is sent to the chat_id of the context's update. Use $opt param to specify a different
529
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
530
     *
531
     * More on https://core.telegram.org/bots/api#senddice
532
     *
533
     * @param array|null $opt
534
     * @return PromiseInterface
535
     */
536
    public function sendDice(?array $opt = []): PromiseInterface
537
    {
538
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
539
        return $this->callApi("sendDice", $opt, Message::class);
540
    }
541
542
    /**
543
     * Use this method when you need to tell the user that something is happening on the bot's side. The status is set for 5
544
     * seconds or less (when a message arrives from your bot, Telegram clients clear its typing status). Returns True on
545
     * success.
546
     *
547
     * By default the chat action is sent to the chat_id of the context's update. Use $opt param to specify a different
548
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
549
     *
550
     * More on https://core.telegram.org/bots/api#sendchataction
551
     *
552
     * @param string $action
553
     * @param array|null $opt
554
     * @return PromiseInterface
555
     */
556
    public function sendChatAction(string $action, ?array $opt = []): PromiseInterface
557
    {
558
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
559
        $required = compact("action");
560
        $params = array_merge($required, $opt);
561
        return $this->callApi("sendChatAction", $params);
562
    }
563
564
    /**
565
     * Use this method to get a list of profile pictures for a user. Returns a @see UserProfilePhotos object.
566
     *
567
     * More on https://core.telegram.org/bots/api#getuserprofilephotos
568
     *
569
     * @param int $user_id
570
     * @param array|null $opt
571
     * @return PromiseInterface
572
     */
573
    public function getUserProfilePhotos(int $user_id, ?array $opt = []): PromiseInterface
574
    {
575
        $required = compact("user_id");
576
        $params = array_merge($required, $opt);
577
        return $this->callApi("getUserProfilePhotos", $params, UserProfilePhotos::class);
578
    }
579
580
    /**
581
     * Use this method to get basic info about a file and prepare it for downloading. For the moment, bots can download
582
     * files of up to 20MB in size. On success, a @see File object is returned. The file can then be downloaded via the link
583
     * https://api.telegram.org/file/bot&lt;token&gt;/&lt;file_path&gt;, where &lt;file_path&gt; is taken from the
584
     * response. It is guaranteed that the link will be valid for at least 1 hour. When the link expires, a new one can
585
     * be requested by calling getFile again.
586
     *
587
     * More on https://core.telegram.org/bots/api#getfile
588
     *
589
     * @param string $file_id
590
     * @param array|null $opt
591
     * @return PromiseInterface
592
     */
593
    public function getFile(string $file_id, ?array $opt = []): PromiseInterface
594
    {
595
        $required = compact("file_id");
596
        $params = array_merge($required, $opt);
597
        return $this->callApi("getFile", $params, File::class);
598
    }
599
600
    /**
601
     * Use this method to kick a user from a group, a supergroup or a channel. In the case of supergroups and channels, the
602
     * user will not be able to return to the group on their own using invite links, etc., unless unbanned first. The bot
603
     * must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on
604
     * success.
605
     *
606
     * More on https://core.telegram.org/bots/api#kickchatmember
607
     *
608
     * @param int $chat_id
609
     * @param int $user_id
610
     * @param array|null $opt
611
     * @return PromiseInterface
612
     */
613
    public function kickChatMember(int $chat_id, int $user_id, ?array $opt = []): PromiseInterface
614
    {
615
        $required = compact("chat_id", "user_id");
616
        $params = array_merge($required, $opt);
617
        return $this->callApi("kickChatMember", $params);
618
    }
619
620
    /**
621
     * Use this method to unban a previously kicked user in a supergroup or channel. The user will not return to the group
622
     * or channel automatically, but will be able to join via link, etc. The bot must be an administrator for this to
623
     * work. Returns True on success.
624
     *
625
     * More on https://core.telegram.org/bots/api#unbanchatmember
626
     *
627
     * @param int $chat_id
628
     * @param int $user_id
629
     * @param array|null $opt
630
     * @return PromiseInterface
631
     */
632
    public function unbanChatMember(int $chat_id, int $user_id, ?array $opt = []): PromiseInterface
633
    {
634
        $required = compact("chat_id", "user_id");
635
        $params = array_merge($required, $opt);
636
        return $this->callApi("unbanChatMember", $params);
637
    }
638
639
    /**
640
     * Use this method to restrict a user in a supergroup. The bot must be an administrator in the supergroup for this to
641
     * work and must have the appropriate admin rights. Pass True for all permissions to lift restrictions from a user.
642
     * Returns True on success.
643
     *
644
     * More on https://core.telegram.org/bots/api#restrictchatmember
645
     *
646
     * @param int $chat_id
647
     * @param int $user_id
648
     * @param $permissions
649
     * @param array|null $opt
650
     * @return PromiseInterface
651
     */
652
    public function restrictChatMember(int $chat_id, int $user_id, $permissions, ?array $opt = []): PromiseInterface
653
    {
654
        $required = compact("chat_id", "user_id", "permissions");
655
        $params = array_merge($required, $opt);
656
        return $this->callApi("restrictChatMember", $params);
657
    }
658
659
    /**
660
     * Use this method to promote or demote a user in a supergroup or a channel. The bot must be an administrator in the
661
     * chat for this to work and must have the appropriate admin rights. Pass False for all boolean parameters to demote
662
     * a user. Returns True on success.
663
     *
664
     * More on https://core.telegram.org/bots/api#promotechatmember
665
     *
666
     * @param int $chat_id
667
     * @param int $user_id
668
     * @param array|null $opt
669
     * @return PromiseInterface
670
     */
671
    public function promoteChatMember(int $chat_id, int $user_id, ?array $opt = []): PromiseInterface
672
    {
673
        $required = compact("chat_id", "user_id");
674
        $params = array_merge($required, $opt);
675
        return $this->callApi("promoteChatMember", $params);
676
    }
677
678
    /**
679
     * Use this method to set a custom title for an administrator in a supergroup promoted by the bot. Returns True on success.
680
     *
681
     * More on https://core.telegram.org/bots/api#setchatadministratorcustomtitle
682
     *
683
     * @param int $chat_id
684
     * @param int $user_id
685
     * @param string $custom_title
686
     * @param array|null $opt
687
     * @return PromiseInterface
688
     */
689
    public function setChatAdministratorCustomTitle(int $chat_id, int $user_id, string $custom_title, ?array $opt = []): PromiseInterface
690
    {
691
        $required = compact("chat_id", "user_id", "custom_title");
692
        $params = array_merge($required, $opt);
693
        return $this->callApi("setChatAdministratorCustomTitle", $params);
694
    }
695
696
    /**
697
     * Use this method to set default chat permissions for all members. The bot must be an administrator in the group or a
698
     * supergroup for this to work and must have the can_restrict_members admin rights. Returns True on success.
699
     *
700
     * More on https://core.telegram.org/bots/api#setchatpermissions
701
     *
702
     * @param int $chat_id
703
     * @param $permissions
704
     * @param array|null $opt
705
     * @return PromiseInterface
706
     */
707
    public function setChatPermissions(int $chat_id, $permissions, ?array $opt = []): PromiseInterface
708
    {
709
        $required = compact("chat_id", "permissions");
710
        $params = array_merge($required, $opt);
711
        return $this->callApi("setChatPermissions", $params);
712
    }
713
714
    /**
715
     * Use this method to generate a new invite link for a chat; any previously generated link is revoked. The bot must be
716
     * an administrator in the chat for this to work and must have the appropriate admin rights. Returns the new invite
717
     * link as String on success.
718
     *
719
     * More on https://core.telegram.org/bots/api#exportchatinvitelink
720
     *
721
     * @param int $chat_id
722
     * @param array|null $opt
723
     * @return PromiseInterface
724
     */
725
    public function exportChatInviteLink(int $chat_id, ?array $opt = []): PromiseInterface
726
    {
727
        $required = compact("chat_id");
728
        $params = array_merge($required, $opt);
729
        return $this->callApi("exportChatInviteLink", $params);
730
    }
731
732
    /**
733
     * Use this method to set a new profile photo for the chat. Photos can't be changed for private chats. The bot must be
734
     * an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
735
     *
736
     * More on https://core.telegram.org/bots/api#setchatphoto
737
     *
738
     * @param int $chat_id
739
     * @param $photo
740
     * @param array|null $opt
741
     * @return PromiseInterface
742
     */
743
    public function setChatPhoto(int $chat_id, $photo, ?array $opt = []): PromiseInterface
744
    {
745
        $required = compact("chat_id", "photo");
746
        $params = array_merge($required, $opt);
747
        return $this->callApi("setChatPhoto", $params); //bool
748
    }
749
750
    /**
751
     * Use this method to delete a chat photo. Photos can't be changed for private chats. The bot must be an administrator
752
     * in the chat for this to work and must have the appropriate admin rights. Returns True on success.
753
     *
754
     * More on https://core.telegram.org/bots/api#deletechatphoto
755
     *
756
     * @param int $chat_id
757
     * @param array|null $opt
758
     * @return PromiseInterface
759
     */
760
    public function deleteChatPhoto(int $chat_id, ?array $opt = []): PromiseInterface
761
    {
762
        $required = compact("chat_id");
763
        $params = array_merge($required, $opt);
764
        return $this->callApi("deleteChatPhoto", $params);
765
    }
766
767
    /**
768
     * Use this method to change the title of a chat. Titles can't be changed for private chats. The bot must be an
769
     * administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
770
     *
771
     * More on https://core.telegram.org/bots/api#setchattitle
772
     *
773
     * @param int $chat_id
774
     * @param string $title
775
     * @param array|null $opt
776
     * @return PromiseInterface
777
     */
778
    public function setChatTitle(int $chat_id, string $title, ?array $opt = []): PromiseInterface
779
    {
780
        $required = compact("chat_id", "title");
781
        $params = array_merge($required, $opt);
782
        return $this->callApi("setChatTitle", $params);
783
    }
784
785
    /**
786
     * Use this method to change the description of a group, a supergroup or a channel. The bot must be an administrator in
787
     * the chat for this to work and must have the appropriate admin rights. Returns True on success.
788
     *
789
     * More on https://core.telegram.org/bots/api#setchatdescription
790
     *
791
     * @param int $chat_id
792
     * @param array|null $opt
793
     * @return PromiseInterface
794
     */
795
    public function setChatDescription(int $chat_id, ?array $opt = []): PromiseInterface
796
    {
797
        $required = compact("chat_id");
798
        $params = array_merge($required, $opt);
799
        return $this->callApi("setChatDescription", $params);
800
    }
801
802
    /**
803
     * Use this method to pin a message in a group, a supergroup, or a channel. The bot must be an administrator in the chat
804
     * for this to work and must have the 'can_pin_messages' admin right in the supergroup or 'can_edit_messages' admin
805
     * right in the channel. Returns True on success.
806
     *
807
     * More on https://core.telegram.org/bots/api#pinchatmessage
808
     *
809
     * @param int $chat_id
810
     * @param int $message_id
811
     * @param array|null $opt
812
     * @return PromiseInterface
813
     */
814
    public function pinChatMessage(int $chat_id, int $message_id, ?array $opt = []): PromiseInterface
815
    {
816
        $required = compact("chat_id", "message_id");
817
        $params = array_merge($required, $opt);
818
        return $this->callApi("pinChatMessage", $params);
819
    }
820
821
    /**
822
     * Use this method to unpin a message in a group, a supergroup, or a channel. The bot must be an administrator in the
823
     * chat for this to work and must have the 'can_pin_messages' admin right in the supergroup or 'can_edit_messages'
824
     * admin right in the channel. Returns True on success.
825
     *
826
     * More on https://core.telegram.org/bots/api#unpinchatmessage
827
     *
828
     * @param int $chat_id
829
     * @param array|null $opt
830
     * @return PromiseInterface
831
     */
832
    public function unpinChatMessage(int $chat_id, ?array $opt = []): PromiseInterface
833
    {
834
        $required = compact("chat_id");
835
        $params = array_merge($required, $opt);
836
        return $this->callApi("unpinChatMessage", $params);
837
    }
838
839
    /**
840
     * Use this method for your bot to leave a group, supergroup or channel. Returns True on success.
841
     *
842
     * More on https://core.telegram.org/bots/api#leavechat
843
     *
844
     * @param int $chat_id
845
     * @param array|null $opt
846
     * @return PromiseInterface
847
     */
848
    public function leaveChat(int $chat_id, ?array $opt = []): PromiseInterface
849
    {
850
        $required = compact("chat_id");
851
        $params = array_merge($required, $opt);
852
        return $this->callApi("leaveChat", $params);
853
    }
854
855
    /**
856
     * Use this method to get up to date information about the chat (current name of the user for one-on-one conversations,
857
     * current username of a user, group or channel, etc.). Returns a @see Chat object on success.
858
     *
859
     * More on https://core.telegram.org/bots/api#getchat
860
     *
861
     * @param int $chat_id
862
     * @param array|null $opt
863
     * @return PromiseInterface
864
     */
865
    public function getChat(int $chat_id, ?array $opt = []): PromiseInterface
866
    {
867
        $required = compact("chat_id");
868
        $params = array_merge($required, $opt);
869
        return $this->callApi("getChat", $params, Chat::class);
870
    }
871
872
    /**
873
     * Use this method to get a list of administrators in a chat. On success, returns an Array of @see ChatMember objects that
874
     * contains information about all chat administrators except other bots. If the chat is a group or a supergroup and
875
     * no administrators were appointed, only the creator will be returned.
876
     *
877
     * More on https://core.telegram.org/bots/api#getchatadministrators
878
     *
879
     * @param int $chat_id
880
     * @param array|null $opt
881
     * @return PromiseInterface
882
     */
883
    public function getChatAdministrators(int $chat_id, ?array $opt = []): PromiseInterface
884
    {
885
        $required = compact("chat_id");
886
        $params = array_merge($required, $opt);
887
        return $this->callApi("getChatAdministrators", $params, ChatMember::class);
888
    }
889
890
    /**
891
     * Use this method to get the number of members in a chat. Returns Int on success.
892
     *
893
     * More on https://core.telegram.org/bots/api#getchatmemberscount
894
     *
895
     * @param int $chat_id
896
     * @param array|null $opt
897
     * @return PromiseInterface
898
     */
899
    public function getChatMembersCount(int $chat_id, ?array $opt = []): PromiseInterface
900
    {
901
        $required = compact("chat_id");
902
        $params = array_merge($required, $opt);
903
        return $this->callApi("getChatMembersCount", $params); //integer
904
    }
905
906
    /**
907
     * Use this method to get information about a member of a chat. Returns a @see ChatMember object on success.
908
     *
909
     * More on https://core.telegram.org/bots/api#getchatmember
910
     *
911
     * @param int $chat_id
912
     * @param int $user_id
913
     * @param array|null $opt
914
     * @return PromiseInterface
915
     */
916
    public function getChatMember(int $chat_id, int $user_id, ?array $opt = []): PromiseInterface
917
    {
918
        $required = compact("chat_id", "user_id");
919
        $params = array_merge($required, $opt);
920
        return $this->callApi("getChatMember", $params, ChatMember::class);
921
    }
922
923
    /**
924
     * Use this method to set a new group sticker set for a supergroup. The bot must be an administrator in the chat for
925
     * this to work and must have the appropriate admin rights. Use the field can_set_sticker_set optionally returned in
926
     * getChat requests to check if the bot can use this method. Returns True on success.
927
     *
928
     * More on https://core.telegram.org/bots/api#setchatstickerset
929
     *
930
     * @param int $chat_id
931
     * @param string $sticker_set_name
932
     * @param array|null $opt
933
     * @return PromiseInterface
934
     */
935
    public function setChatStickerSet(int $chat_id, string $sticker_set_name, ?array $opt = []): PromiseInterface
936
    {
937
        $required = compact("chat_id", "sticker_set_name");
938
        $params = array_merge($required, $opt);
939
        return $this->callApi("setChatStickerSet", $params);
940
    }
941
942
    /**
943
     * Use this method to delete a group sticker set from a supergroup. The bot must be an administrator in the chat for
944
     * this to work and must have the appropriate admin rights. Use the field can_set_sticker_set optionally returned in
945
     * getChat requests to check if the bot can use this method. Returns True on success.
946
     *
947
     * More on https://core.telegram.org/bots/api#deletechatstickerset
948
     *
949
     * @param int $chat_id
950
     * @param array|null $opt
951
     * @return PromiseInterface
952
     */
953
    public function deleteChatStickerSet(int $chat_id, ?array $opt = []): PromiseInterface
954
    {
955
        $required = compact("chat_id");
956
        $params = array_merge($required, $opt);
957
        return $this->callApi("deleteChatStickerSet", $params);
958
    }
959
960
    /**
961
     * Use this method to send answers to callback queries sent from inline keyboards. The answer will be displayed to the
962
     * user as a notification at the top of the chat screen or as an alert. On success, True is returned.
963
     *
964
     * By default it replies to the callback_query_id of the context's update. Use $opt param to specify a different
965
     * callback_query_id. Eg. $opt = ['callback_query_id' => 'abcdefgh'];
966
     *
967
     * More on https://core.telegram.org/bots/api#answercallbackquery
968
     *
969
     * @param array|null $opt
970
     * @return PromiseInterface
971
     */
972
    public function answerCallbackQuery(?array $opt = []): PromiseInterface
973
    {
974
        $opt['callback_query_id'] = $opt['callback_query_id'] ?? $this->update->getCallbackQuery()->getId();
975
        return $this->callApi("answerCallbackQuery", $opt);
976
    }
977
978
    /**
979
     * Use this method to change the list of the bot's commands. Returns True on success.
980
     *
981
     * More on https://core.telegram.org/bots/api#setmycommands
982
     *
983
     * @param $commands
984
     * @param array|null $opt
985
     * @return PromiseInterface
986
     */
987
    public function setMyCommands($commands, ?array $opt = []): PromiseInterface
988
    {
989
        $required = compact("commands");
990
        $params = array_merge($required, $opt);
991
        return $this->callApi("setMyCommands", $params);
992
    }
993
994
    /**
995
     * Use this method to edit text and game messages. On success, if edited message is sent by the bot, the edited @see Message
996
     * is returned, otherwise True is returned.
997
     *
998
     * By default the chat_id taken from the context's update. Use $opt param to specify a different
999
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
1000
     *
1001
     * By default the message_id is taken from the context's update. Use $opt param to specify a different
1002
     * message_id. Eg. $opt = ['message_id' => 123456789];
1003
     *
1004
     * More on https://core.telegram.org/bots/api#editmessagetext
1005
     *
1006
     * @param string $text
1007
     * @param array|null $opt = [
1008
     *     'reply_markup' => ['inline_keyboard' => [[
1009
     *          ['callback_data' => 'data', 'text' => 'text']
1010
     *      ]]]
1011
     * ]
1012
     * @return PromiseInterface
1013
     */
1014
    public function editMessageText(string $text, ?array $opt = []): PromiseInterface
1015
    {
1016
        // if the user doesn't provide inline_message_id, chat_id or message_id the framework tries to resolve them
1017
        // based on the Update's type
1018
        if (!isset($opt['inline_message_id']) && !isset($opt['chat_id']) && !isset($opt['message_id'])) {
1019
            if ($this->update->getUpdateType() == CallbackQuery::class) {
1020
                $cbQuery = $this->update->getCallbackQuery();
1021
                if ($cbQuery->getInlineMessageId()) {
1022
                    $opt['inline_message_id'] = $cbQuery->getInlineMessageId();
1023
                } else if ($cbQuery->getMessage()) {
1024
                    $opt['message_id'] = $cbQuery->getMessage()->getMessageId();
1025
                }
1026
            }
1027
            // set chat_id only if inline_message_id wasn't set
1028
            if (!isset($opt['inline_message_id']) && $this->update->getEffectiveChat()) {
1029
                $opt['chat_id'] = $this->update->getEffectiveChat()->getId();
1030
            }
1031
        }
1032
        $required = compact("text");
1033
        $params = array_merge($required, $opt);
1034
        return $this->callApi("editMessageText", $params, Message::class);
1035
    }
1036
1037
    /**
1038
     * Use this method to edit captions of messages. On success, if edited message is sent by the bot, the edited @see Message is
1039
     * returned, otherwise True is returned.
1040
     *
1041
     * More on https://core.telegram.org/bots/api#editmessagecaption
1042
     *
1043
     * @param array|null $opt
1044
     * @return PromiseInterface
1045
     */
1046
    public function editMessageCaption(?array $opt = []): PromiseInterface
1047
    {
1048
        return $this->callApi("editMessageCaption", $opt, Message::class);
1049
    }
1050
1051
    /**
1052
     * Use this method to edit animation, audio, document, photo, or video messages. If a message is a part of a message
1053
     * album, then it can be edited only to a photo or a video. Otherwise, message type can be changed arbitrarily. When
1054
     * inline message is edited, new file can't be uploaded. Use previously uploaded file via its file_id or specify a
1055
     * URL. On success, if the edited message was sent by the bot, the edited @see Message is returned, otherwise True is
1056
     * returned.
1057
     *
1058
     * More on https://core.telegram.org/bots/api#editmessagemedia
1059
     *
1060
     * @param $media
1061
     * @param array|null $opt
1062
     * @return PromiseInterface
1063
     */
1064
    public function editMessageMedia($media, ?array $opt = []): PromiseInterface
1065
    {
1066
        $required = compact("media");
1067
        $params = array_merge($required, $opt);
1068
        return $this->callApi("editMessageMedia", $params, Message::class);
1069
    }
1070
1071
    /**
1072
     * Use this method to edit only the reply markup of messages. On success, if edited message is sent by the bot, the
1073
     * edited @see Message is returned, otherwise True is returned.
1074
     *
1075
     * More on https://core.telegram.org/bots/api#editmessagereplymarkup
1076
     *
1077
     * @param array|null $opt
1078
     * @return PromiseInterface
1079
     */
1080
    public function editMessageReplyMarkup(?array $opt = []): PromiseInterface
1081
    {
1082
        return $this->callApi("editMessageReplyMarkup", $opt, Message::class);
1083
    }
1084
1085
    /**
1086
     * Use this method to stop a poll which was sent by the bot. On success, the stopped @see Poll with the final results is
1087
     * returned.
1088
     *
1089
     * More on https://core.telegram.org/bots/api#stoppoll
1090
     *
1091
     * @param int $chat_id
1092
     * @param int $message_id
1093
     * @param array|null $opt
1094
     * @return PromiseInterface
1095
     */
1096
    public function stopPoll(int $chat_id, int $message_id, ?array $opt = []): PromiseInterface
1097
    {
1098
        $required = compact("chat_id", "message_id");
1099
        $params = array_merge($required, $opt);
1100
        return $this->callApi("stopPoll", $params, Poll::class);
1101
    }
1102
1103
    /**
1104
     * Use this method to delete a message, including service messages, with the following limitations:- A message can only
1105
     * be deleted if it was sent less than 48 hours ago.- A dice message in a private chat can only be deleted if it was
1106
     * sent more than 24 hours ago.- Bots can delete outgoing messages in private chats, groups, and supergroups.- Bots
1107
     * can delete incoming messages in private chats.- Bots granted can_post_messages permissions can delete outgoing
1108
     * messages in channels.- If the bot is an administrator of a group, it can delete any message there.- If the bot has
1109
     * can_delete_messages permission in a supergroup or a channel, it can delete any message there.Returns True on
1110
     * success.
1111
     *
1112
     * More on https://core.telegram.org/bots/api#deletemessage
1113
     *
1114
     * @param int $chat_id
1115
     * @param int $message_id
1116
     * @param array|null $opt
1117
     * @return PromiseInterface
1118
     */
1119
    public function deleteMessage(int $chat_id, int $message_id, ?array $opt = []): PromiseInterface
1120
    {
1121
        $required = compact("chat_id", "message_id");
1122
        $params = array_merge($required, $opt);
1123
        return $this->callApi("deleteMessage", $params);
1124
    }
1125
1126
    /**
1127
     * Use this method to send static .WEBP or animated .TGS stickers. On success, the sent @see Message is returned.
1128
     *
1129
     * The sticker param can be either a string or a @see InputFile. Note that if you use the latter the file reading
1130
     * operation is synchronous, so the main thread is blocked.
1131
     * To make it asynchronous see https://github.com/badfarm/zanzara/wiki#working-with-files.
1132
     *
1133
     * By default the sticker is sent to the chat_id of the context's update. Use $opt param to specify a different
1134
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
1135
     *
1136
     * More on https://core.telegram.org/bots/api#sendsticker
1137
     *
1138
     * @param $sticker
1139
     * @param array|null $opt
1140
     * @return PromiseInterface
1141
     */
1142
    public function sendSticker($sticker, ?array $opt = []): PromiseInterface
1143
    {
1144
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
1145
        $required = compact("sticker");
1146
        $params = array_merge($required, $opt);
1147
        return $this->callApi("sendSticker", $params, Message::class);
1148
    }
1149
1150
    /**
1151
     * Use this method to get a sticker set. On success, a @see StickerSet object is returned.
1152
     *
1153
     * More on https://core.telegram.org/bots/api#getstickerset
1154
     *
1155
     * @param string $name
1156
     * @param array|null $opt
1157
     * @return PromiseInterface
1158
     */
1159
    public function getStickerSet(string $name, ?array $opt = []): PromiseInterface
1160
    {
1161
        $required = compact("name");
1162
        $params = array_merge($required, $opt);
1163
        return $this->callApi("getStickerSet", $params, StickerSet::class);
1164
    }
1165
1166
    /**
1167
     * Use this method to upload a .PNG file with a sticker for later use in createNewStickerSet and addStickerToSet methods
1168
     * (can be used multiple times). Returns the uploaded @see File on success.
1169
     *
1170
     * More on https://core.telegram.org/bots/api#uploadstickerfile
1171
     *
1172
     * @param int $user_id
1173
     * @param $png_sticker
1174
     * @param array|null $opt
1175
     * @return PromiseInterface
1176
     */
1177
    public function uploadStickerFile(int $user_id, $png_sticker, ?array $opt = []): PromiseInterface
1178
    {
1179
        $required = compact("user_id", "png_sticker");
1180
        $params = array_merge($required, $opt);
1181
        return $this->callApi("uploadStickerFile", $params, File::class);
1182
    }
1183
1184
    /**
1185
     * Use this method to create a new sticker set owned by a user. The bot will be able to edit the sticker set thus
1186
     * created. You must use exactly one of the fields png_sticker or tgs_sticker. Returns True on success.
1187
     *
1188
     * The png_sticker param can be either a string or a @see InputFile. Note that if you use the latter the file reading
1189
     * operation is synchronous, so the main thread is blocked.
1190
     * To make it asynchronous see https://github.com/badfarm/zanzara/wiki#working-with-files.
1191
     *
1192
     * More on https://core.telegram.org/bots/api#createnewstickerset
1193
     *
1194
     * @param int $user_id
1195
     * @param string $name
1196
     * @param string $title
1197
     * @param string $emojis
1198
     * @param array|null $opt
1199
     * @return PromiseInterface
1200
     */
1201
    public function createNewStickerSet(int $user_id, string $name, string $title, string $emojis, ?array $opt = []): PromiseInterface
1202
    {
1203
        $required = compact("user_id", "name", "title", "emojis");
1204
        $params = array_merge($required, $opt);
1205
        return $this->callApi("createNewStickerSet", $params);
1206
    }
1207
1208
    /**
1209
     * Use this method to add a new sticker to a set created by the bot. You must use exactly one of the fields png_sticker
1210
     * or tgs_sticker. Animated stickers can be added to animated sticker sets and only to them. Animated sticker sets
1211
     * can have up to 50 stickers. Static sticker sets can have up to 120 stickers. Returns True on success.
1212
     *
1213
     * The png_sticker param can be either a string or a @see InputFile. Note that if you use the latter the file reading
1214
     * operation is synchronous, so the main thread is blocked.
1215
     * To make it asynchronous see https://github.com/badfarm/zanzara/wiki#working-with-files.
1216
     *
1217
     * More on https://core.telegram.org/bots/api#addstickertoset
1218
     *
1219
     * @param int $user_id
1220
     * @param string $name
1221
     * @param $png_sticker
1222
     * @param string $emojis
1223
     * @param array|null $opt
1224
     * @return PromiseInterface
1225
     */
1226
    public function addStickerToSet(int $user_id, string $name, $png_sticker, string $emojis, ?array $opt = []): PromiseInterface
1227
    {
1228
        $required = compact("user_id", "name", "png_sticker", "emojis");
1229
        $params = array_merge($required, $opt);
1230
        return $this->callApi("addStickerToSet", $params);
1231
    }
1232
1233
    /**
1234
     * Use this method to move a sticker in a set created by the bot to a specific position. Returns True on success.
1235
     *
1236
     * More on https://core.telegram.org/bots/api#setstickerpositioninset
1237
     *
1238
     * @param string $sticker
1239
     * @param int $position
1240
     * @param array|null $opt
1241
     * @return PromiseInterface
1242
     */
1243
    public function setStickerPositionInSet(string $sticker, int $position, ?array $opt = []): PromiseInterface
1244
    {
1245
        $required = compact("sticker", "position");
1246
        $params = array_merge($required, $opt);
1247
        return $this->callApi("setStickerPositionInSet", $params);
1248
    }
1249
1250
    /**
1251
     * Use this method to delete a sticker from a set created by the bot. Returns True on success.
1252
     *
1253
     * More on https://core.telegram.org/bots/api#deletestickerfromset
1254
     *
1255
     * @param string $sticker
1256
     * @param array|null $opt
1257
     * @return PromiseInterface
1258
     */
1259
    public function deleteStickerFromSet(string $sticker, ?array $opt = []): PromiseInterface
1260
    {
1261
        $required = compact("sticker");
1262
        $params = array_merge($required, $opt);
1263
        return $this->callApi("deleteStickerFromSet", $params);
1264
    }
1265
1266
    /**
1267
     * Use this method to set the thumbnail of a sticker set. Animated thumbnails can be set for animated sticker sets only.
1268
     * Returns True on success.
1269
     *
1270
     * The thumb param in $opt can be either a string or a @see InputFile. Note that if you use the latter the file reading
1271
     * operation is synchronous, so the main thread is blocked.
1272
     * To make it asynchronous see https://github.com/badfarm/zanzara/wiki#working-with-files.
1273
     *
1274
     * More on https://core.telegram.org/bots/api#setstickersetthumb
1275
     *
1276
     * @param string $name
1277
     * @param int $user_id
1278
     * @param array|null $opt
1279
     * @return PromiseInterface
1280
     */
1281
    public function setStickerSetThumb(string $name, int $user_id, ?array $opt = []): PromiseInterface
1282
    {
1283
        $required = compact("name", "user_id");
1284
        $params = array_merge($required, $opt);
1285
        return $this->callApi("setStickerSetThumb", $params);
1286
    }
1287
1288
    /**
1289
     * Use this method to send answers to an inline query. On success, True is returned.No more than 50 results per query
1290
     * are allowed.
1291
     *
1292
     * By default it replies to the inline_query_id of the context's update. Use $opt param to specify a different
1293
     * inline_query_id. Eg. $opt = ['inline_query_id' => 'abcdefgh'];
1294
     *
1295
     * More on https://core.telegram.org/bots/api#answerinlinequery
1296
     *
1297
     * @param $results
1298
     * @param array|null $opt
1299
     * @return PromiseInterface
1300
     */
1301
    public function answerInlineQuery($results, ?array $opt = []): PromiseInterface
1302
    {
1303
        $opt['inline_query_id'] = $opt['inline_query_id'] ?? $this->update->getInlineQuery()->getId();
1304
        $required = compact("results");
1305
        $params = array_merge($required, $opt);
1306
        return $this->callApi("answerInlineQuery", $params);
1307
    }
1308
1309
    /**
1310
     * Use this method to send invoices. On success, the sent @see Message is returned.
1311
     *
1312
     * By default the invoice is sent to the chat_id of the context's update. Use $opt param to specify a different
1313
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
1314
     *
1315
     * More on https://core.telegram.org/bots/api#sendinvoice
1316
     *
1317
     * @param string $title
1318
     * @param string $description
1319
     * @param string $payload
1320
     * @param string $provider_token
1321
     * @param string $start_parameter
1322
     * @param string $currency
1323
     * @param $prices
1324
     * @param array|null $opt
1325
     * @return PromiseInterface
1326
     */
1327
    public function sendInvoice(string $title, string $description, string $payload, string $provider_token, string $start_parameter, string $currency, $prices, ?array $opt = []): PromiseInterface
1328
    {
1329
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
1330
        $required = compact("title", "description", "payload", "provider_token", "start_parameter", "currency", "prices");
1331
        $params = array_merge($required, $opt);
1332
        return $this->callApi("sendInvoice", $params, Message::class);
1333
    }
1334
1335
    /**
1336
     * @param array $params
1337
     * @return PromiseInterface
1338
     */
1339
    public function doSendInvoice(array $params): PromiseInterface
1340
    {
1341
        $params['chat_id'] = $params['chat_id'] ?? $this->update->getEffectiveChat()->getId();
1342
        return $this->callApi("sendInvoice", $params, Message::class);
1343
    }
1344
1345
    /**
1346
     * If you sent an invoice requesting a shipping address and the parameter is_flexible was specified, the Bot API will
1347
     * send an Update with a shipping_query field to the bot. Use this method to reply to shipping queries. On success,
1348
     * True is returned.
1349
     *
1350
     * By default it replies to the shipping_query_id of the context's update. Use $opt param to specify a different
1351
     * shipping_query_id. Eg. $opt = ['shipping_query_id' => 'abcdefgh'];
1352
     *
1353
     * More on https://core.telegram.org/bots/api#answershippingquery
1354
     *
1355
     * @param $ok
1356
     * @param array|null $opt
1357
     * @return PromiseInterface
1358
     */
1359
    public function answerShippingQuery($ok, ?array $opt = []): PromiseInterface
1360
    {
1361
        $opt['shipping_query_id'] = $opt['shipping_query_id'] ?? $this->update->getShippingQuery()->getId();
1362
        $required = compact("ok");
1363
        $params = array_merge($required, $opt);
1364
        return $this->callApi("answerShippingQuery", $params);
1365
    }
1366
1367
    /**
1368
     * Once the user has confirmed their payment and shipping details, the Bot API sends the final confirmation in the form
1369
     * of an Update with the field pre_checkout_query. Use this method to respond to such pre-checkout queries. On
1370
     * success, True is returned. Note: The Bot API must receive an answer within 10 seconds after the pre-checkout query
1371
     * was sent.
1372
     *
1373
     * By default it replies to the pre_checkout_query_id of the context's update. Use $opt param to specify a different
1374
     * pre_checkout_query_id. Eg. $opt = ['pre_checkout_query_id' => 'abcdefgh'];
1375
     *
1376
     * More on https://core.telegram.org/bots/api#answerprecheckoutquery
1377
     *
1378
     * @param $ok
1379
     * @param array|null $opt
1380
     * @return PromiseInterface
1381
     */
1382
    public function answerPreCheckoutQuery($ok, ?array $opt = []): PromiseInterface
1383
    {
1384
        $opt['pre_checkout_query_id'] = $opt['pre_checkout_query_id'] ?? $this->update->getPreCheckoutQuery()->getId();
1385
        $required = compact("ok");
1386
        $params = array_merge($required, $opt);
1387
        return $this->callApi("answerPreCheckoutQuery", $params);
1388
    }
1389
1390
    /**
1391
     * Informs a user that some of the Telegram Passport elements they provided contains errors. The user will not be able
1392
     * to re-submit their Passport to you until the errors are fixed (the contents of the field for which you returned
1393
     * the error must change). Returns True on success.
1394
     *
1395
     * More on https://core.telegram.org/bots/api#setpassportdataerrors
1396
     *
1397
     * @param int $user_id
1398
     * @param $errors
1399
     * @param array|null $opt
1400
     * @return PromiseInterface
1401
     */
1402
    public function setPassportDataErrors(int $user_id, $errors, ?array $opt = []): PromiseInterface
1403
    {
1404
        $required = compact("user_id", "errors");
1405
        $params = array_merge($required, $opt);
1406
        return $this->callApi("setPassportDataErrors", $params);
1407
    }
1408
1409
    /**
1410
     * Use this method to send a game. On success, the sent @see Message is returned.
1411
     *
1412
     * By default the game is sent to the chat_id of the context's update. Use $opt param to specify a different
1413
     * chat_id. Eg. $opt = ['chat_id' => 123456789];
1414
     *
1415
     * More on https://core.telegram.org/bots/api#sendgame
1416
     *
1417
     * @param string $game_short_name
1418
     * @param array|null $opt
1419
     * @return PromiseInterface
1420
     */
1421
    public function sendGame(string $game_short_name, ?array $opt = []): PromiseInterface
1422
    {
1423
        $opt['chat_id'] = $opt['chat_id'] ?? $this->update->getEffectiveChat()->getId();
1424
        $required = compact("game_short_name");
1425
        $params = array_merge($required, $opt);
1426
        return $this->callApi("sendGame", $params, Message::class);
1427
    }
1428
1429
    /**
1430
     * Use this method to set the score of the specified user in a game. On success, if the message was sent by the bot,
1431
     * returns the edited @see Message, otherwise returns True. Returns an error, if the new score is not greater than the
1432
     * user's current score in the chat and force is False.
1433
     *
1434
     * More on https://core.telegram.org/bots/api#setgamescore
1435
     *
1436
     * @param int $user_id
1437
     * @param int $score
1438
     * @param array|null $opt
1439
     * @return PromiseInterface
1440
     */
1441
    public function setGameScore(int $user_id, int $score, ?array $opt = []): PromiseInterface
1442
    {
1443
        $required = compact("user_id", "score");
1444
        $params = array_merge($required, $opt);
1445
        return $this->callApi("setGameScore", $params, Message::class);
1446
    }
1447
1448
    /**
1449
     * Use this method to get data for high score tables. Will return the score of the specified user and several of his
1450
     * neighbors in a game. On success, returns an Array of @see GameHighScore objects.
1451
     *
1452
     * More on https://core.telegram.org/bots/api#getgamehighscores
1453
     *
1454
     * @param int $user_id
1455
     * @param array|null $opt
1456
     * @return PromiseInterface
1457
     */
1458
    public function getGameHighScores(int $user_id, ?array $opt = []): PromiseInterface
1459
    {
1460
        $required = compact("user_id");
1461
        $params = array_merge($required, $opt);
1462
        return $this->callApi("getGameHighScores", $params, GameHighScore::class);
1463
    }
1464
1465
    /**
1466
     * @param string $method
1467
     * @param array $params
1468
     * @param string $class
1469
     * @param string[] $headers
1470
     * @return PromiseInterface
1471
     */
1472
    public function callApi(string $method, array $params = [], string $class = 'Scalar', $headers = ["Content-type" => "application/json"])
1473
    {
1474
        if ($this->container->get(Config::class)->getParseMode() && !isset($params['parse_mode'])) {
1475
            $params['parse_mode'] = $this->container->get(Config::class)->getParseMode();
1476
        }
1477
        foreach ($params as $param) {
1478
            if ($param instanceof InputFile) {
1479
1480
                $async = $this->container->get(Config::class)->isReactFileSystem();
1481
1482
                if ($async) {
1483
                    return $this->prepareMultipartDataAsync($params)->then(function ($result) use ($method) {
1484
                        $headers = array("Content-Length" => $result->getSize(), "Content-Type" => "multipart/form-data; boundary={$result->getBoundary()}");
1485
                        return $this->browser->post($method, $headers, $result);
1486
                    });
1487
                } else {
1488
                    $multipart = $this->prepareMultipartData($params);
1489
                    $headers = array("Content-Length" => $multipart->getSize(), "Content-Type" => "multipart/form-data; boundary={$multipart->getBoundary()}");
1490
                    return $this->browser->post($method, $headers, $multipart);
1491
                }
1492
            }
1493
        }
1494
        return $this->wrapPromise($this->browser->post($method, $headers, json_encode($params)), $method, $params, $class);
1495
    }
1496
1497
    /**
1498
     *
1499
     * Create MultipartStream, iterate over params to find InputFile
1500
     *
1501
     * @param $params
1502
     * @return PromiseInterface
1503
     */
1504
    private function prepareMultipartDataAsync($params)
1505
    {
1506
        $filesystem = $this->container->get(Filesystem::class);
1507
        $multipart_data = [];
1508
        $promises = [];
1509
        foreach ($params as $key => $value) {
1510
1511
            if ($value instanceof InputFile) {
1512
                array_push($promises, $filesystem->getContents($value->getPath())->then(function ($contents) use ($value, $multipart_data, $key) {
0 ignored issues
show
Unused Code introduced by
The import $multipart_data is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
1513
                    $data = ['name' => $key];
1514
                    $data['contents'] = $contents;
1515
                    $data['filename'] = basename($value->getPath());
1516
                    return $data;
1517
                }, function ($error) {
1518
                    $this->container->get(ZanzaraLogger::class)->error($error);
1519
                    return $error;
1520
                }));
1521
1522
            } else {
1523
                $data = ['name' => $key];
1524
                $data['contents'] = strval($value);
1525
                array_push($multipart_data, $data);
1526
            }
1527
        }
1528
1529
        return all($promises)->then(function ($files) use ($multipart_data) {
1530
            foreach ($files as $key => $value) {
1531
                array_push($multipart_data, $value);
1532
            }
1533
            return new MultipartStream($multipart_data);
1534
        }, function ($error) {
1535
            $this->container->get(ZanzaraLogger::class)->error($error);
1536
            return $error;
1537
        });
1538
    }
1539
1540
    private function prepareMultipartData($params)
1541
    {
1542
        $multipart_data = [];
1543
        foreach ($params as $key => $value) {
1544
            $data = ['name' => $key];
1545
            if ($value instanceof InputFile) {
1546
                if (file_exists($value->getPath())) {
1547
                    $fileData = file_get_contents($value->getPath());
1548
                    $data['contents'] = $fileData;
1549
                    $data['filename'] = basename($value->getPath());
1550
                } else {
1551
                    $this->container->get(ZanzaraLogger::class)->error("File not found: {$value->getPath()}");
1552
                }
1553
1554
            } else {
1555
                $data['contents'] = strval($value);
1556
            }
1557
            array_push($multipart_data, $data);
1558
        }
1559
        return new MultipartStream($multipart_data);
1560
    }
1561
1562
    /**
1563
     * ZanzaraPromise class was removed since it swallowed the promise chain.
1564
     * We actually have to call the original promise, get the response and propagate the casted response along
1565
     * the promise chain.
1566
     * For the rejected promise, we have to cast the original exception to a TelegramException and rethrow it
1567
     * in order to let the user receive the exception in his onRejected function.
1568
     *
1569
     * Unfortunately, we don't have control on user's callback input parameter anymore. In this way the user
1570
     * needs to manage the otherwise() promise callback to see the error.
1571
     *
1572
     * @param PromiseInterface $promise
1573
     * @param string $method
1574
     * @param array $params
1575
     * @param string $class
1576
     * @return PromiseInterface
1577
     */
1578
    private function wrapPromise(PromiseInterface $promise, string $method, array $params = [], string $class = "Scalar"): PromiseInterface
1579
    {
1580
        $mapper = $this->container->get(ZanzaraMapper::class);
1581
        $logger = $this->container->get(ZanzaraLogger::class);
1582
1583
        return $promise
1584
            ->then(function (ResponseInterface $response) use ($class, $mapper) {
1585
                $json = (string)$response->getBody();
1586
                $object = json_decode($json);
1587
1588
                if (is_scalar($object->result) && $class === "Scalar") {
1589
                    return $object->result;
1590
                }
1591
1592
                return $mapper->mapObject($object->result, $class);
1593
            }, function ($e) use ($method, $params, $logger, $mapper) {
1594
                if ($e instanceof ResponseException) {
1595
                    $json = (string)$e->getResponse()->getBody();
1596
                    $e = $mapper->mapJson($json, TelegramException::class);
1597
                }
1598
                $logger->errorTelegramApi($method, $params, $e);
1599
                throw $e;
1600
            });
1601
    }
1602
1603
}