Completed
Push — develop ( f09bf5...728003 )
by Armando
24s queued 13s
created

Telegram::getCommandObject()   C

Complexity

Conditions 12
Paths 35

Size

Total Lines 44
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 24.6381

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 12
eloc 27
c 2
b 0
f 0
nc 35
nop 2
dl 0
loc 44
ccs 15
cts 27
cp 0.5556
crap 24.6381
rs 6.9666

How to fix   Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This file is part of the TelegramBot package.
5
 *
6
 * (c) Avtandil Kikabidze aka LONGMAN <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Longman\TelegramBot;
13
14 1
defined('TB_BASE_PATH') || define('TB_BASE_PATH', __DIR__);
15 1
defined('TB_BASE_COMMANDS_PATH') || define('TB_BASE_COMMANDS_PATH', TB_BASE_PATH . '/Commands');
16
17
use Exception;
18
use Longman\TelegramBot\Commands\AdminCommand;
19
use Longman\TelegramBot\Commands\Command;
20
use Longman\TelegramBot\Commands\SystemCommand;
21
use Longman\TelegramBot\Commands\UserCommand;
22
use Longman\TelegramBot\Entities\ServerResponse;
23
use Longman\TelegramBot\Entities\Update;
24
use Longman\TelegramBot\Exception\TelegramException;
25
use PDO;
26
use RecursiveDirectoryIterator;
27
use RecursiveIteratorIterator;
28
use RegexIterator;
29
30
class Telegram
31
{
32
    /**
33
     * Version
34
     *
35
     * @var string
36
     */
37
    protected $version = '0.64.0';
38
39
    /**
40
     * Telegram API key
41
     *
42
     * @var string
43
     */
44
    protected $api_key = '';
45
46
    /**
47
     * Telegram Bot username
48
     *
49
     * @var string
50
     */
51
    protected $bot_username = '';
52
53
    /**
54
     * Telegram Bot id
55
     *
56
     * @var string
57
     */
58
    protected $bot_id = '';
59
60
    /**
61
     * Raw request data (json) for webhook methods
62
     *
63
     * @var string
64
     */
65
    protected $input;
66
67
    /**
68
     * Custom commands paths
69
     *
70
     * @var array
71
     */
72
    protected $commands_paths = [];
73
74
    /**
75
     * Custom commands objects
76
     *
77
     * @var array
78
     */
79
    protected $commands_objects = [];
80
81
    /**
82
     * Current Update object
83
     *
84
     * @var Update
85
     */
86
    protected $update;
87
88
    /**
89
     * Upload path
90
     *
91
     * @var string
92
     */
93
    protected $upload_path;
94
95
    /**
96
     * Download path
97
     *
98
     * @var string
99
     */
100
    protected $download_path;
101
102
    /**
103
     * MySQL integration
104
     *
105
     * @var bool
106
     */
107
    protected $mysql_enabled = false;
108
109
    /**
110
     * PDO object
111
     *
112
     * @var PDO
113
     */
114
    protected $pdo;
115
116
    /**
117
     * Commands config
118
     *
119
     * @var array
120
     */
121
    protected $commands_config = [];
122
123
    /**
124
     * Admins list
125
     *
126
     * @var array
127
     */
128
    protected $admins_list = [];
129
130
    /**
131
     * ServerResponse of the last Command execution
132
     *
133
     * @var ServerResponse
134
     */
135
    protected $last_command_response;
136
137
    /**
138
     * Check if runCommands() is running in this session
139
     *
140
     * @var bool
141
     */
142
    protected $run_commands = false;
143
144
    /**
145
     * Is running getUpdates without DB enabled
146
     *
147
     * @var bool
148
     */
149
    protected $getupdates_without_database = false;
150
151
    /**
152
     * Last update ID
153
     * Only used when running getUpdates without a database
154
     *
155
     * @var int
156
     */
157
    protected $last_update_id;
158
159
    /**
160
     * The command to be executed when there's a new message update and nothing more suitable is found
161
     */
162
    const GENERIC_MESSAGE_COMMAND = 'genericmessage';
163
164
    /**
165
     * The command to be executed by default (when no other relevant commands are applicable)
166
     */
167
    const GENERIC_COMMAND = 'generic';
168
169
    /**
170
     * Update filter
171
     * Filter updates
172
     *
173
     * @var callback
174
     */
175
    protected $update_filter;
176
177
    /**
178
     * Telegram constructor.
179
     *
180
     * @param string $api_key
181
     * @param string $bot_username
182
     *
183
     * @throws TelegramException
184
     */
185 30
    public function __construct($api_key, $bot_username = '')
186
    {
187 30
        if (empty($api_key)) {
188 1
            throw new TelegramException('API KEY not defined!');
189
        }
190 30
        preg_match('/(\d+):[\w\-]+/', $api_key, $matches);
191 30
        if (!isset($matches[1])) {
192 1
            throw new TelegramException('Invalid API KEY defined!');
193
        }
194 30
        $this->bot_id  = $matches[1];
195 30
        $this->api_key = $api_key;
196
197 30
        if (!empty($bot_username)) {
198 30
            $this->bot_username = $bot_username;
199
        }
200
201
        //Add default system commands path
202 30
        $this->addCommandsPath(TB_BASE_COMMANDS_PATH . '/SystemCommands');
203
204 30
        Request::initialize($this);
205 30
    }
206
207
    /**
208
     * Initialize Database connection
209
     *
210
     * @param array  $credential
211
     * @param string $table_prefix
212
     * @param string $encoding
213
     *
214
     * @return Telegram
215
     * @throws TelegramException
216
     */
217 9
    public function enableMySql(array $credential, $table_prefix = null, $encoding = 'utf8mb4')
218
    {
219 9
        $this->pdo = DB::initialize($credential, $this, $table_prefix, $encoding);
220 9
        ConversationDB::initializeConversation();
221 9
        $this->mysql_enabled = true;
222
223 9
        return $this;
224
    }
225
226
    /**
227
     * Initialize Database external connection
228
     *
229
     * @param PDO    $external_pdo_connection PDO database object
230
     * @param string $table_prefix
231
     *
232
     * @return Telegram
233
     * @throws TelegramException
234
     */
235
    public function enableExternalMySql($external_pdo_connection, $table_prefix = null)
236
    {
237
        $this->pdo = DB::externalInitialize($external_pdo_connection, $this, $table_prefix);
238
        ConversationDB::initializeConversation();
239
        $this->mysql_enabled = true;
240
241
        return $this;
242
    }
243
244
    /**
245
     * Get commands list
246
     *
247
     * @return array $commands
248
     * @throws TelegramException
249
     */
250 1
    public function getCommandsList()
251
    {
252 1
        $commands = [];
253
254 1
        foreach ($this->commands_paths as $path) {
255
            try {
256
                //Get all "*Command.php" files
257 1
                $files = new RegexIterator(
258 1
                    new RecursiveIteratorIterator(
259 1
                        new RecursiveDirectoryIterator($path)
260
                    ),
261 1
                    '/^.+Command.php$/'
262
                );
263
264 1
                foreach ($files as $file) {
265
                    //Remove "Command.php" from filename
266 1
                    $command      = $this->sanitizeCommand(substr($file->getFilename(), 0, -11));
267 1
                    $command_name = mb_strtolower($command);
268
269 1
                    if (array_key_exists($command_name, $commands)) {
270
                        continue;
271
                    }
272
273 1
                    require_once $file->getPathname();
274
275 1
                    $command_obj = $this->getCommandObject($command, $file->getPathname());
276 1
                    if ($command_obj instanceof Command) {
277 1
                        $commands[$command_name] = $command_obj;
278
                    }
279
                }
280
            } catch (Exception $e) {
281
                throw new TelegramException('Error getting commands from path: ' . $path, $e);
0 ignored issues
show
Bug introduced by
$e of type Exception is incompatible with the type integer expected by parameter $code of Longman\TelegramBot\Exce...xception::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

281
                throw new TelegramException('Error getting commands from path: ' . $path, /** @scrutinizer ignore-type */ $e);
Loading history...
282
            }
283
        }
284
285 1
        return $commands;
286
    }
287
288
    /**
289
     * Get an object instance of the passed command
290
     *
291
     * @param string $command
292
     * @param string $filepath
293
     *
294
     * @return Command|null
295
     */
296 1
    public function getCommandObject($command, $filepath = null)
297
    {
298 1
        if (isset($this->commands_objects[$command])) {
299
            return $this->commands_objects[$command];
300
        }
301
302 1
        $which = ['System'];
303 1
        $this->isAdmin() && $which[] = 'Admin';
304 1
        $which[] = 'User';
305
306 1
        foreach ($which as $auth) {
307 1
            if ($filepath) {
308 1
                $command_namespace = $this->getFileNamespace($filepath);
309
            } else {
310
                $command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands';
311
            }
312 1
            $command_class = $command_namespace . '\\' . $this->ucfirstUnicode($command) . 'Command';
313
314 1
            if (class_exists($command_class)) {
315 1
                $command_obj = new $command_class($this, $this->update);
316
317 1
                switch ($auth) {
318 1
                    case 'System':
319 1
                        if ($command_obj instanceof SystemCommand) {
320 1
                            return $command_obj;
321
                        }
322
                        break;
323
324
                    case 'Admin':
325
                        if ($command_obj instanceof AdminCommand) {
326
                            return $command_obj;
327
                        }
328
                        break;
329
330
                    case 'User':
331
                        if ($command_obj instanceof UserCommand) {
332
                            return $command_obj;
333
                        }
334
                        break;
335
                }
336
            }
337
        }
338
339
        return null;
340
    }
341
342
    /**
343
     * Get namespace from php file by src path
344
     *
345
     * @param string $src (absolute path to file)
346
     *
347
     * @return string ("Longman\TelegramBot\Commands\SystemCommands" for example)
348
     */
349 1
    protected function getFileNamespace($src)
350
    {
351 1
        $content = file_get_contents($src);
352 1
        if (preg_match('#^namespace\s+(.+?);#m', $content, $m)) {
353 1
            return $m[1];
354
        }
355
        return null;
356
    }
357
358
    /**
359
     * Set custom input string for debug purposes
360
     *
361
     * @param string $input (json format)
362
     *
363
     * @return Telegram
364
     */
365
    public function setCustomInput($input)
366
    {
367
        $this->input = $input;
368
369
        return $this;
370
    }
371
372
    /**
373
     * Get custom input string for debug purposes
374
     *
375
     * @return string
376
     */
377
    public function getCustomInput()
378
    {
379
        return $this->input;
380
    }
381
382
    /**
383
     * Get the ServerResponse of the last Command execution
384
     *
385
     * @return ServerResponse
386
     */
387
    public function getLastCommandResponse()
388
    {
389
        return $this->last_command_response;
390
    }
391
392
    /**
393
     * Handle getUpdates method
394
     *
395
     * @param int|null $limit
396
     * @param int|null $timeout
397
     *
398
     * @return ServerResponse
399
     * @throws TelegramException
400
     */
401
    public function handleGetUpdates($limit = null, $timeout = null)
402
    {
403
        if (empty($this->bot_username)) {
404
            throw new TelegramException('Bot Username is not defined!');
405
        }
406
407
        if (!DB::isDbConnected() && !$this->getupdates_without_database) {
408
            return new ServerResponse(
409
                [
410
                    'ok'          => false,
411
                    'description' => 'getUpdates needs MySQL connection! (This can be overridden - see documentation)',
412
                ],
413
                $this->bot_username
414
            );
415
        }
416
417
        $offset = 0;
418
419
        //Take custom input into account.
420
        if ($custom_input = $this->getCustomInput()) {
421
            $response = new ServerResponse(json_decode($custom_input, true), $this->bot_username);
422
        } else {
423
            if (DB::isDbConnected() && $last_update = DB::selectTelegramUpdate(1)) {
424
                //Get last update id from the database
425
                $last_update = reset($last_update);
426
427
                $this->last_update_id = isset($last_update['id']) ? $last_update['id'] : null;
428
            }
429
430
            if ($this->last_update_id !== null) {
431
                $offset = $this->last_update_id + 1;    //As explained in the telegram bot API documentation
432
            }
433
434
            $response = Request::getUpdates(
435
                [
436
                    'offset'  => $offset,
437
                    'limit'   => $limit,
438
                    'timeout' => $timeout,
439
                ]
440
            );
441
        }
442
443
        if ($response->isOk()) {
444
            $results = $response->getResult();
445
446
            //Process all updates
447
            /** @var Update $result */
448
            foreach ($results as $result) {
449
                $this->processUpdate($result);
450
            }
451
452
            if (!DB::isDbConnected() && !$custom_input && $this->last_update_id !== null && $offset === 0) {
453
                //Mark update(s) as read after handling
454
                Request::getUpdates(
455
                    [
456
                        'offset'  => $this->last_update_id + 1,
457
                        'limit'   => 1,
458
                        'timeout' => $timeout,
459
                    ]
460
                );
461
            }
462
        }
463
464
        return $response;
465
    }
466
467
    /**
468
     * Handle bot request from webhook
469
     *
470
     * @return bool
471
     *
472
     * @throws TelegramException
473
     */
474
    public function handle()
475
    {
476
        if (empty($this->bot_username)) {
477
            throw new TelegramException('Bot Username is not defined!');
478
        }
479
480
        $this->input = Request::getInput();
481
482
        if (empty($this->input)) {
483
            throw new TelegramException('Input is empty!');
484
        }
485
486
        $post = json_decode($this->input, true);
487
        if (empty($post)) {
488
            throw new TelegramException('Invalid JSON!');
489
        }
490
491
        if ($response = $this->processUpdate(new Update($post, $this->bot_username))) {
492
            return $response->isOk();
493
        }
494
495
        return false;
496
    }
497
498
    /**
499
     * Get the command name from the command type
500
     *
501
     * @param string $type
502
     *
503
     * @return string
504
     */
505
    protected function getCommandFromType($type)
506
    {
507
        return $this->ucfirstUnicode(str_replace('_', '', $type));
508
    }
509
510
    /**
511
     * Process bot Update request
512
     *
513
     * @param Update $update
514
     *
515
     * @return ServerResponse
516
     * @throws TelegramException
517
     */
518 1
    public function processUpdate(Update $update)
519
    {
520 1
        $this->update         = $update;
521 1
        $this->last_update_id = $update->getUpdateId();
522
523 1
        if (is_callable($this->update_filter)) {
524 1
            $reason = 'Update denied by update_filter';
525
            try {
526 1
                $allowed = (bool) call_user_func_array($this->update_filter, [$update, $this, &$reason]);
527
            } catch (\Exception $e) {
528
                $allowed = false;
529
            }
530
531 1
            if (!$allowed) {
532 1
                TelegramLog::debug($reason);
533 1
                return new ServerResponse(['ok' => false, 'description' => 'denied'], null);
534
            }
535
        }
536
537
        //Load admin commands
538
        if ($this->isAdmin()) {
539
            $this->addCommandsPath(TB_BASE_COMMANDS_PATH . '/AdminCommands', false);
540
        }
541
542
        //Make sure we have an up-to-date command list
543
        //This is necessary to "require" all the necessary command files!
544
        $this->commands_objects = $this->getCommandsList();
545
546
        //If all else fails, it's a generic message.
547
        $command = self::GENERIC_MESSAGE_COMMAND;
548
549
        $update_type = $this->update->getUpdateType();
550
        if ($update_type === 'message') {
551
            $message = $this->update->getMessage();
552
            $type    = $message->getType();
553
554
            // Let's check if the message object has the type field we're looking for...
555
            $command_tmp = $type === 'command' ? $message->getCommand() : $this->getCommandFromType($type);
556
            // ...and if a fitting command class is available.
557
            $command_obj = $this->getCommandObject($command_tmp);
558
559
            // Empty usage string denotes a non-executable command.
560
            // @see https://github.com/php-telegram-bot/core/issues/772#issuecomment-388616072
561
            if (
562
                ($command_obj === null && $type === 'command')
563
                || ($command_obj !== null && $command_obj->getUsage() !== '')
564
            ) {
565
                $command = $command_tmp;
566
            }
567
        } else {
568
            $command = $this->getCommandFromType($update_type);
569
        }
570
571
        //Make sure we don't try to process update that was already processed
572
        $last_id = DB::selectTelegramUpdate(1, $this->update->getUpdateId());
573
        if ($last_id && count($last_id) === 1) {
574
            TelegramLog::debug('Duplicate update received, processing aborted!');
575
            return Request::emptyResponse();
576
        }
577
578
        DB::insertRequest($this->update);
579
580
        return $this->executeCommand($command);
581
    }
582
583
    /**
584
     * Execute /command
585
     *
586
     * @param string $command
587
     *
588
     * @return ServerResponse
589
     * @throws TelegramException
590
     */
591
    public function executeCommand($command)
592
    {
593
        $command = mb_strtolower($command);
594
595
        if (isset($this->commands_objects[$command])) {
596
            $command_obj = $this->commands_objects[$command];
597
        } else {
598
            $command_obj = $this->getCommandObject($command);
599
        }
600
601
        if (!$command_obj || !$command_obj->isEnabled()) {
602
            //Failsafe in case the Generic command can't be found
603
            if ($command === self::GENERIC_COMMAND) {
604
                throw new TelegramException('Generic command missing!');
605
            }
606
607
            //Handle a generic command or non existing one
608
            $this->last_command_response = $this->executeCommand(self::GENERIC_COMMAND);
609
        } else {
610
            //execute() method is executed after preExecute()
611
            //This is to prevent executing a DB query without a valid connection
612
            $this->last_command_response = $command_obj->preExecute();
613
        }
614
615
        return $this->last_command_response;
616
    }
617
618
    /**
619
     * Sanitize Command
620
     *
621
     * @param string $command
622
     *
623
     * @return string
624
     */
625 1
    protected function sanitizeCommand($command)
626
    {
627 1
        return str_replace(' ', '', $this->ucwordsUnicode(str_replace('_', ' ', $command)));
628
    }
629
630
    /**
631
     * Enable a single Admin account
632
     *
633
     * @param int $admin_id Single admin id
634
     *
635
     * @return Telegram
636
     */
637 1
    public function enableAdmin($admin_id)
638
    {
639 1
        if (!is_int($admin_id) || $admin_id <= 0) {
0 ignored issues
show
introduced by
The condition is_int($admin_id) is always true.
Loading history...
640 1
            TelegramLog::error('Invalid value "' . $admin_id . '" for admin.');
641 1
        } elseif (!in_array($admin_id, $this->admins_list, true)) {
642 1
            $this->admins_list[] = $admin_id;
643
        }
644
645 1
        return $this;
646
    }
647
648
    /**
649
     * Enable a list of Admin Accounts
650
     *
651
     * @param array $admin_ids List of admin ids
652
     *
653
     * @return Telegram
654
     */
655 1
    public function enableAdmins(array $admin_ids)
656
    {
657 1
        foreach ($admin_ids as $admin_id) {
658 1
            $this->enableAdmin($admin_id);
659
        }
660
661 1
        return $this;
662
    }
663
664
    /**
665
     * Get list of admins
666
     *
667
     * @return array
668
     */
669 1
    public function getAdminList()
670
    {
671 1
        return $this->admins_list;
672
    }
673
674
    /**
675
     * Check if the passed user is an admin
676
     *
677
     * If no user id is passed, the current update is checked for a valid message sender.
678
     *
679
     * @param int|null $user_id
680
     *
681
     * @return bool
682
     */
683 1
    public function isAdmin($user_id = null)
684
    {
685 1
        if ($user_id === null && $this->update !== null) {
686
            //Try to figure out if the user is an admin
687
            $update_methods = [
688
                'getMessage',
689
                'getEditedMessage',
690
                'getChannelPost',
691
                'getEditedChannelPost',
692
                'getInlineQuery',
693
                'getChosenInlineResult',
694
                'getCallbackQuery',
695
            ];
696
            foreach ($update_methods as $update_method) {
697
                $object = call_user_func([$this->update, $update_method]);
698
                if ($object !== null && $from = $object->getFrom()) {
699
                    $user_id = $from->getId();
700
                    break;
701
                }
702
            }
703
        }
704
705 1
        return ($user_id === null) ? false : in_array($user_id, $this->admins_list, true);
706
    }
707
708
    /**
709
     * Check if user required the db connection
710
     *
711
     * @return bool
712
     */
713
    public function isDbEnabled()
714
    {
715
        return $this->mysql_enabled;
716
    }
717
718
    /**
719
     * Add a single custom commands path
720
     *
721
     * @param string $path   Custom commands path to add
722
     * @param bool   $before If the path should be prepended or appended to the list
723
     *
724
     * @return Telegram
725
     */
726 30
    public function addCommandsPath($path, $before = true)
727
    {
728 30
        if (!is_dir($path)) {
729 1
            TelegramLog::error('Commands path "' . $path . '" does not exist.');
730 30
        } elseif (!in_array($path, $this->commands_paths, true)) {
731 30
            if ($before) {
732 30
                array_unshift($this->commands_paths, $path);
733
            } else {
734
                $this->commands_paths[] = $path;
735
            }
736
        }
737
738 30
        return $this;
739
    }
740
741
    /**
742
     * Add multiple custom commands paths
743
     *
744
     * @param array $paths  Custom commands paths to add
745
     * @param bool  $before If the paths should be prepended or appended to the list
746
     *
747
     * @return Telegram
748
     */
749 1
    public function addCommandsPaths(array $paths, $before = true)
750
    {
751 1
        foreach ($paths as $path) {
752 1
            $this->addCommandsPath($path, $before);
753
        }
754
755 1
        return $this;
756
    }
757
758
    /**
759
     * Return the list of commands paths
760
     *
761
     * @return array
762
     */
763 1
    public function getCommandsPaths()
764
    {
765 1
        return $this->commands_paths;
766
    }
767
768
    /**
769
     * Set custom upload path
770
     *
771
     * @param string $path Custom upload path
772
     *
773
     * @return Telegram
774
     */
775
    public function setUploadPath($path)
776
    {
777
        $this->upload_path = $path;
778
779
        return $this;
780
    }
781
782
    /**
783
     * Get custom upload path
784
     *
785
     * @return string
786
     */
787
    public function getUploadPath()
788
    {
789
        return $this->upload_path;
790
    }
791
792
    /**
793
     * Set custom download path
794
     *
795
     * @param string $path Custom download path
796
     *
797
     * @return Telegram
798
     */
799
    public function setDownloadPath($path)
800
    {
801
        $this->download_path = $path;
802
803
        return $this;
804
    }
805
806
    /**
807
     * Get custom download path
808
     *
809
     * @return string
810
     */
811
    public function getDownloadPath()
812
    {
813
        return $this->download_path;
814
    }
815
816
    /**
817
     * Set command config
818
     *
819
     * Provide further variables to a particular commands.
820
     * For example you can add the channel name at the command /sendtochannel
821
     * Or you can add the api key for external service.
822
     *
823
     * @param string $command
824
     * @param array  $config
825
     *
826
     * @return Telegram
827
     */
828 13
    public function setCommandConfig($command, array $config)
829
    {
830 13
        $this->commands_config[$command] = $config;
831
832 13
        return $this;
833
    }
834
835
    /**
836
     * Get command config
837
     *
838
     * @param string $command
839
     *
840
     * @return array
841
     */
842 14
    public function getCommandConfig($command)
843
    {
844 14
        return isset($this->commands_config[$command]) ? $this->commands_config[$command] : [];
845
    }
846
847
    /**
848
     * Get API key
849
     *
850
     * @return string
851
     */
852 1
    public function getApiKey()
853
    {
854 1
        return $this->api_key;
855
    }
856
857
    /**
858
     * Get Bot name
859
     *
860
     * @return string
861
     */
862 2
    public function getBotUsername()
863
    {
864 2
        return $this->bot_username;
865
    }
866
867
    /**
868
     * Get Bot Id
869
     *
870
     * @return string
871
     */
872
    public function getBotId()
873
    {
874
        return $this->bot_id;
875
    }
876
877
    /**
878
     * Get Version
879
     *
880
     * @return string
881
     */
882
    public function getVersion()
883
    {
884
        return $this->version;
885
    }
886
887
    /**
888
     * Set Webhook for bot
889
     *
890
     * @param string $url
891
     * @param array  $data Optional parameters.
892
     *
893
     * @return ServerResponse
894
     * @throws TelegramException
895
     */
896
    public function setWebhook($url, array $data = [])
897
    {
898
        if (empty($url)) {
899
            throw new TelegramException('Hook url is empty!');
900
        }
901
902
        $data        = array_intersect_key($data, array_flip([
903
            'certificate',
904
            'max_connections',
905
            'allowed_updates',
906
        ]));
907
        $data['url'] = $url;
908
909
        // If the certificate is passed as a path, encode and add the file to the data array.
910
        if (!empty($data['certificate']) && is_string($data['certificate'])) {
911
            $data['certificate'] = Request::encodeFile($data['certificate']);
912
        }
913
914
        $result = Request::setWebhook($data);
915
916
        if (!$result->isOk()) {
917
            throw new TelegramException(
918
                'Webhook was not set! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
919
            );
920
        }
921
922
        return $result;
923
    }
924
925
    /**
926
     * Delete any assigned webhook
927
     *
928
     * @return mixed
929
     * @throws TelegramException
930
     */
931
    public function deleteWebhook()
932
    {
933
        $result = Request::deleteWebhook();
934
935
        if (!$result->isOk()) {
936
            throw new TelegramException(
937
                'Webhook was not deleted! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
938
            );
939
        }
940
941
        return $result;
942
    }
943
944
    /**
945
     * Replace function `ucwords` for UTF-8 characters in the class definition and commands
946
     *
947
     * @param string $str
948
     * @param string $encoding (default = 'UTF-8')
949
     *
950
     * @return string
951
     */
952 1
    protected function ucwordsUnicode($str, $encoding = 'UTF-8')
953
    {
954 1
        return mb_convert_case($str, MB_CASE_TITLE, $encoding);
955
    }
956
957
    /**
958
     * Replace function `ucfirst` for UTF-8 characters in the class definition and commands
959
     *
960
     * @param string $str
961
     * @param string $encoding (default = 'UTF-8')
962
     *
963
     * @return string
964
     */
965 1
    protected function ucfirstUnicode($str, $encoding = 'UTF-8')
966
    {
967 1
        return mb_strtoupper(mb_substr($str, 0, 1, $encoding), $encoding)
968 1
            . mb_strtolower(mb_substr($str, 1, mb_strlen($str), $encoding), $encoding);
969
    }
970
971
    /**
972
     * Enable requests limiter
973
     *
974
     * @param array $options
975
     *
976
     * @return Telegram
977
     * @throws TelegramException
978
     */
979
    public function enableLimiter(array $options = [])
980
    {
981
        Request::setLimiter(true, $options);
982
983
        return $this;
984
    }
985
986
    /**
987
     * Run provided commands
988
     *
989
     * @param array $commands
990
     *
991
     * @throws TelegramException
992
     */
993
    public function runCommands($commands)
994
    {
995
        if (!is_array($commands) || empty($commands)) {
0 ignored issues
show
introduced by
The condition is_array($commands) is always true.
Loading history...
996
            throw new TelegramException('No command(s) provided!');
997
        }
998
999
        $this->run_commands = true;
1000
1001
        $result = Request::getMe();
1002
1003
        if ($result->isOk()) {
1004
            $result = $result->getResult();
1005
1006
            $bot_id       = $result->getId();
1007
            $bot_name     = $result->getFirstName();
1008
            $bot_username = $result->getUsername();
1009
        } else {
1010
            $bot_id       = $this->getBotId();
1011
            $bot_name     = $this->getBotUsername();
1012
            $bot_username = $this->getBotUsername();
1013
        }
1014
1015
        // Give bot access to admin commands
1016
        $this->enableAdmin($bot_id);
1017
1018
        $newUpdate = static function ($text = '') use ($bot_id, $bot_name, $bot_username) {
1019
            return new Update(
1020
                [
1021
                    'update_id' => 0,
1022
                    'message'   => [
1023
                        'message_id' => 0,
1024
                        'from'       => [
1025
                            'id'         => $bot_id,
1026
                            'first_name' => $bot_name,
1027
                            'username'   => $bot_username,
1028
                        ],
1029
                        'date'       => time(),
1030
                        'chat'       => [
1031
                            'id'   => $bot_id,
1032
                            'type' => 'private',
1033
                        ],
1034
                        'text'       => $text,
1035
                    ],
1036
                ]
1037
            );
1038
        };
1039
1040
        $this->update = $newUpdate();   // Required for isAdmin() check inside getCommandObject()
1041
        $this->commands_objects = $this->getCommandsList();       // Load up-to-date commands list
1042
1043
        foreach ($commands as $command) {
1044
            $this->update = $newUpdate($command);
1045
1046
            $this->executeCommand($this->update->getMessage()->getCommand());
1047
        }
1048
    }
1049
1050
    /**
1051
     * Is this session initiated by runCommands()
1052
     *
1053
     * @return bool
1054
     */
1055
    public function isRunCommands()
1056
    {
1057
        return $this->run_commands;
1058
    }
1059
1060
    /**
1061
     * Switch to enable running getUpdates without a database
1062
     *
1063
     * @param bool $enable
1064
     */
1065
    public function useGetUpdatesWithoutDatabase($enable = true)
1066
    {
1067
        $this->getupdates_without_database = $enable;
1068
    }
1069
1070
    /**
1071
     * Return last update id
1072
     *
1073
     * @return int
1074
     */
1075
    public function getLastUpdateId()
1076
    {
1077
        return $this->last_update_id;
1078
    }
1079
1080
    /**
1081
     * Set an update filter callback
1082
     *
1083
     * @param callable $callback
1084
     *
1085
     * @return Telegram
1086
     */
1087 1
    public function setUpdateFilter(callable $callback)
1088
    {
1089 1
        $this->update_filter = $callback;
1090
1091 1
        return $this;
1092
    }
1093
1094
    /**
1095
     * Return update filter callback
1096
     *
1097
     * @return callable|null
1098
     */
1099
    public function getUpdateFilter()
1100
    {
1101
        return $this->update_filter;
1102
    }
1103
}
1104