Passed
Pull Request — develop (#973)
by Armando
02:05
created

Telegram   F

Complexity

Total Complexity 104

Size/Duplication

Total Lines 951
Duplicated Lines 0 %

Test Coverage

Coverage 33.2%

Importance

Changes 0
Metric Value
eloc 254
dl 0
loc 951
ccs 86
cts 259
cp 0.332
rs 2
c 0
b 0
f 0
wmc 104

41 Methods

Rating   Name   Duplication   Size   Complexity  
A getCustomInput() 0 3 1
A enableMySql() 0 7 1
A enableExternalMySql() 0 7 1
A getCommandsList() 0 36 6
A setCustomInput() 0 5 1
A getLastCommandResponse() 0 3 1
A getCommandObject() 0 14 4
A __construct() 0 20 4
C handleGetUpdates() 0 64 15
A setUploadPath() 0 5 1
A deleteWebhook() 0 11 2
A setDownloadPath() 0 5 1
A getCommandFromType() 0 3 1
A addCommandsPath() 0 13 4
B processUpdate() 0 45 7
B isAdmin() 0 23 7
A getAdminList() 0 3 1
A getCommandConfig() 0 3 2
A getApiKey() 0 3 1
A isDbEnabled() 0 6 2
A ucfirstUnicode() 0 4 1
A isRunCommands() 0 3 1
A getBotId() 0 3 1
A addCommandsPaths() 0 7 2
A getBotUsername() 0 3 1
A executeCommand() 0 20 4
A enableLimiter() 0 5 1
A setCommandConfig() 0 5 1
A setWebhook() 0 27 5
A getUploadPath() 0 3 1
A useGetUpdatesWithoutDatabase() 0 3 1
A getDownloadPath() 0 3 1
A enableAdmin() 0 9 4
A getCommandsPaths() 0 3 1
A getVersion() 0 3 1
A handle() 0 22 5
A ucwordsUnicode() 0 3 1
A runCommands() 0 48 5
A sanitizeCommand() 0 3 1
A enableAdmins() 0 7 2
A getLastUpdateId() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like Telegram often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Telegram, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * This file is part of the TelegramBot package.
4
 *
5
 * (c) Avtandil Kikabidze aka LONGMAN <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Longman\TelegramBot;
12
13 1
defined('TB_BASE_PATH') || define('TB_BASE_PATH', __DIR__);
14 1
defined('TB_BASE_COMMANDS_PATH') || define('TB_BASE_COMMANDS_PATH', TB_BASE_PATH . '/Commands');
15
16
use Exception;
17
use Longman\TelegramBot\Commands\Command;
18
use Longman\TelegramBot\Entities\ServerResponse;
19
use Longman\TelegramBot\Entities\Update;
20
use Longman\TelegramBot\Exception\TelegramException;
21
use PDO;
22
use RecursiveDirectoryIterator;
23
use RecursiveIteratorIterator;
24
use RegexIterator;
25
26
class Telegram
27
{
28
    /**
29
     * Version
30
     *
31
     * @var string
32
     */
33
    protected $version = '0.57.0';
34
35
    /**
36
     * Telegram API key
37
     *
38
     * @var string
39
     */
40
    protected $api_key = '';
41
42
    /**
43
     * Telegram Bot username
44
     *
45
     * @var string
46
     */
47
    protected $bot_username = '';
48
49
    /**
50
     * Telegram Bot id
51
     *
52
     * @var string
53
     */
54
    protected $bot_id = '';
55
56
    /**
57
     * Raw request data (json) for webhook methods
58
     *
59
     * @var string
60
     */
61
    protected $input;
62
63
    /**
64
     * Custom commands paths
65
     *
66
     * @var array
67
     */
68
    protected $commands_paths = [];
69
70
    /**
71
     * Current Update object
72
     *
73
     * @var Update
74
     */
75
    protected $update;
76
77
    /**
78
     * Upload path
79
     *
80
     * @var string
81
     */
82
    protected $upload_path;
83
84
    /**
85
     * Download path
86
     *
87
     * @var string
88
     */
89
    protected $download_path;
90
91
    /**
92
     * MySQL integration
93
     *
94
     * @var boolean
95
     */
96
    protected $mysql_enabled = false;
97
98
    /**
99
     * PDO object
100
     *
101
     * @var PDO
102
     */
103
    protected $pdo;
104
105
    /**
106
     * Commands config
107
     *
108
     * @var array
109
     */
110
    protected $commands_config = [];
111
112
    /**
113
     * Admins list
114
     *
115
     * @var array
116
     */
117
    protected $admins_list = [];
118
119
    /**
120
     * ServerResponse of the last Command execution
121
     *
122
     * @var ServerResponse
123
     */
124
    protected $last_command_response;
125
126
    /**
127
     * Check if runCommands() is running in this session
128
     *
129
     * @var boolean
130
     */
131
    protected $run_commands = false;
132
133
    /**
134
     * Is running getUpdates without DB enabled
135
     *
136
     * @var bool
137
     */
138
    protected $getupdates_without_database = false;
139
140
    /**
141
     * Last update ID
142
     * Only used when running getUpdates without a database
143
     *
144
     * @var integer
145
     */
146
    protected $last_update_id = null;
147
148
    /**
149
     * Telegram constructor.
150
     *
151
     * @param string $api_key
152
     * @param string $bot_username
153
     *
154
     * @throws TelegramException
155
     */
156 30
    public function __construct($api_key, $bot_username = '')
157
    {
158 30
        if (empty($api_key)) {
159 1
            throw new TelegramException('API KEY not defined!');
160
        }
161 30
        preg_match('/(\d+)\:[\w\-]+/', $api_key, $matches);
162 30
        if (!isset($matches[1])) {
163 1
            throw new TelegramException('Invalid API KEY defined!');
164
        }
165 30
        $this->bot_id  = $matches[1];
166 30
        $this->api_key = $api_key;
167
168 30
        if (!empty($bot_username)) {
169 30
            $this->bot_username = $bot_username;
170
        }
171
172
        //Add default system commands path
173 30
        $this->addCommandsPath(TB_BASE_COMMANDS_PATH . '/SystemCommands');
174
175 30
        Request::initialize($this);
176 30
    }
177
178
    /**
179
     * Initialize Database connection
180
     *
181
     * @param array  $credential
182
     * @param string $table_prefix
183
     * @param string $encoding
184
     *
185
     * @return Telegram
186
     * @throws TelegramException
187
     */
188 9
    public function enableMySql(array $credential, $table_prefix = null, $encoding = 'utf8mb4')
189
    {
190 9
        $this->pdo = DB::initialize($credential, $this, $table_prefix, $encoding);
191 9
        ConversationDB::initializeConversation();
192 9
        $this->mysql_enabled = true;
193
194 9
        return $this;
195
    }
196
197
    /**
198
     * Initialize Database external connection
199
     *
200
     * @param PDO    $external_pdo_connection PDO database object
201
     * @param string $table_prefix
202
     *
203
     * @return Telegram
204
     * @throws TelegramException
205
     */
206
    public function enableExternalMySql($external_pdo_connection, $table_prefix = null)
207
    {
208
        $this->pdo = DB::externalInitialize($external_pdo_connection, $this, $table_prefix);
209
        ConversationDB::initializeConversation();
210
        $this->mysql_enabled = true;
211
212
        return $this;
213
    }
214
215
    /**
216
     * Get commands list
217
     *
218
     * @return array $commands
219
     * @throws TelegramException
220
     */
221 1
    public function getCommandsList()
222
    {
223 1
        $commands = [];
224
225 1
        foreach ($this->commands_paths as $path) {
226
            try {
227
                //Get all "*Command.php" files
228 1
                $files = new RegexIterator(
229 1
                    new RecursiveIteratorIterator(
230 1
                        new RecursiveDirectoryIterator($path)
231
                    ),
232 1
                    '/^.+Command.php$/'
233
                );
234
235 1
                foreach ($files as $file) {
236
                    //Remove "Command.php" from filename
237 1
                    $command      = $this->sanitizeCommand(substr($file->getFilename(), 0, -11));
238 1
                    $command_name = strtolower($command);
239
240 1
                    if (array_key_exists($command_name, $commands)) {
241
                        continue;
242
                    }
243
244 1
                    require_once $file->getPathname();
245
246 1
                    $command_obj = $this->getCommandObject($command);
247 1
                    if ($command_obj instanceof Command) {
248 1
                        $commands[$command_name] = $command_obj;
249
                    }
250
                }
251
            } catch (Exception $e) {
252
                throw new TelegramException('Error getting commands from path: ' . $path);
253
            }
254
        }
255
256 1
        return $commands;
257
    }
258
259
    /**
260
     * Get an object instance of the passed command
261
     *
262
     * @param string $command
263
     *
264
     * @return Command|null
265
     */
266 1
    public function getCommandObject($command)
267
    {
268 1
        $which = ['System'];
269 1
        $this->isAdmin() && $which[] = 'Admin';
270 1
        $which[] = 'User';
271
272 1
        foreach ($which as $auth) {
273 1
            $command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands\\' . $this->ucfirstUnicode($command) . 'Command';
274 1
            if (class_exists($command_namespace)) {
275 1
                return new $command_namespace($this, $this->update);
276
            }
277
        }
278
279
        return null;
280
    }
281
282
    /**
283
     * Set custom input string for debug purposes
284
     *
285
     * @param string $input (json format)
286
     *
287
     * @return Telegram
288
     */
289
    public function setCustomInput($input)
290
    {
291
        $this->input = $input;
292
293
        return $this;
294
    }
295
296
    /**
297
     * Get custom input string for debug purposes
298
     *
299
     * @return string
300
     */
301
    public function getCustomInput()
302
    {
303
        return $this->input;
304
    }
305
306
    /**
307
     * Get the ServerResponse of the last Command execution
308
     *
309
     * @return ServerResponse
310
     */
311
    public function getLastCommandResponse()
312
    {
313
        return $this->last_command_response;
314
    }
315
316
    /**
317
     * Handle getUpdates method
318
     *
319
     * @param int|null $limit
320
     * @param int|null $timeout
321
     *
322
     * @return ServerResponse
323
     * @throws TelegramException
324
     */
325
    public function handleGetUpdates($limit = null, $timeout = null)
326
    {
327
        if (empty($this->bot_username)) {
328
            throw new TelegramException('Bot Username is not defined!');
329
        }
330
331
        if (!DB::isDbConnected() && !$this->getupdates_without_database) {
332
            return new ServerResponse(
333
                [
334
                    'ok'          => false,
335
                    'description' => 'getUpdates needs MySQL connection! (This can be overridden - see documentation)',
336
                ],
337
                $this->bot_username
338
            );
339
        }
340
341
        $offset = 0;
342
343
        //Take custom input into account.
344
        if ($custom_input = $this->getCustomInput()) {
345
            $response = new ServerResponse(json_decode($custom_input, true), $this->bot_username);
346
        } else {
347
            if (DB::isDbConnected() && $last_update = DB::selectTelegramUpdate(1)) {
348
                //Get last update id from the database
349
                $last_update = reset($last_update);
350
351
                $this->last_update_id = isset($last_update['id']) ? $last_update['id'] : null;
352
            }
353
354
            if ($this->last_update_id !== null) {
355
                $offset = $this->last_update_id + 1;    //As explained in the telegram bot API documentation
356
            }
357
358
            $response = Request::getUpdates(
359
                [
360
                    'offset'  => $offset,
361
                    'limit'   => $limit,
362
                    'timeout' => $timeout,
363
                ]
364
            );
365
        }
366
367
        if ($response->isOk()) {
368
            $results = $response->getResult();
369
370
            //Process all updates
371
            /** @var Update $result */
372
            foreach ($results as $result) {
373
                $this->processUpdate($result);
374
            }
375
376
            if (!DB::isDbConnected() && !$custom_input && $this->last_update_id !== null && $offset === 0) {
377
                //Mark update(s) as read after handling
378
                Request::getUpdates(
379
                    [
380
                        'offset'  => $this->last_update_id + 1,
381
                        'limit'   => 1,
382
                        'timeout' => $timeout,
383
                    ]
384
                );
385
            }
386
        }
387
388
        return $response;
389
    }
390
391
    /**
392
     * Handle bot request from webhook
393
     *
394
     * @return bool
395
     *
396
     * @throws TelegramException
397
     */
398
    public function handle()
399
    {
400
        if (empty($this->bot_username)) {
401
            throw new TelegramException('Bot Username is not defined!');
402
        }
403
404
        $this->input = Request::getInput();
405
406
        if (empty($this->input)) {
407
            throw new TelegramException('Input is empty!');
408
        }
409
410
        $post = json_decode($this->input, true);
411
        if (empty($post)) {
412
            throw new TelegramException('Invalid JSON!');
413
        }
414
415
        if ($response = $this->processUpdate(new Update($post, $this->bot_username))) {
416
            return $response->isOk();
417
        }
418
419
        return false;
420
    }
421
422
    /**
423
     * Get the command name from the command type
424
     *
425
     * @param string $type
426
     *
427
     * @return string
428
     */
429
    protected function getCommandFromType($type)
430
    {
431
        return $this->ucfirstUnicode(str_replace('_', '', $type));
432
    }
433
434
    /**
435
     * Process bot Update request
436
     *
437
     * @param Update $update
438
     *
439
     * @return ServerResponse
440
     * @throws TelegramException
441
     */
442
    public function processUpdate(Update $update)
443
    {
444
        $this->update         = $update;
445
        $this->last_update_id = $update->getUpdateId();
446
447
        //Load admin commands
448
        if ($this->isAdmin()) {
449
            $this->addCommandsPath(TB_BASE_COMMANDS_PATH . '/AdminCommands', false);
450
        }
451
452
        //Make sure we have an up-to-date command list
453
        //This is necessary to "require" all the necessary command files!
454
        $this->getCommandsList();
455
456
        //If all else fails, it's a generic message.
457
        $command = 'genericmessage';
458
459
        $update_type = $this->update->getUpdateType();
460
        if ($update_type === 'message') {
461
            $message = $this->update->getMessage();
462
            $type    = $message->getType();
463
            if ($type === 'command') {
464
                $command = $message->getCommand();
465
            } else {
466
                // Let's check if the message object has the type field we're looking for
467
                // and if a fitting command class is available.
468
                $command_tmp = $this->getCommandFromType($type);
469
                if ($this->getCommandObject($command_tmp) !== null) {
470
                    $command = $command_tmp;
471
                }
472
            }
473
        } else {
474
            $command = $this->getCommandFromType($update_type);
475
        }
476
477
        //Make sure we don't try to process update that was already processed
478
        $last_id = DB::selectTelegramUpdate(1, $this->update->getUpdateId());
479
        if ($last_id && count($last_id) === 1) {
480
            TelegramLog::debug('Duplicate update received, processing aborted!');
481
            return Request::emptyResponse();
482
        }
483
484
        DB::insertRequest($this->update);
485
486
        return $this->executeCommand($command);
487
    }
488
489
    /**
490
     * Execute /command
491
     *
492
     * @param string $command
493
     *
494
     * @return mixed
495
     * @throws TelegramException
496
     */
497
    public function executeCommand($command)
498
    {
499
        $command     = strtolower($command);
500
        $command_obj = $this->getCommandObject($command);
501
502
        if (!$command_obj || !$command_obj->isEnabled()) {
503
            //Failsafe in case the Generic command can't be found
504
            if ($command === 'generic') {
505
                throw new TelegramException('Generic command missing!');
506
            }
507
508
            //Handle a generic command or non existing one
509
            $this->last_command_response = $this->executeCommand('generic');
510
        } else {
511
            //execute() method is executed after preExecute()
512
            //This is to prevent executing a DB query without a valid connection
513
            $this->last_command_response = $command_obj->preExecute();
514
        }
515
516
        return $this->last_command_response;
517
    }
518
519
    /**
520
     * Sanitize Command
521
     *
522
     * @param string $command
523
     *
524
     * @return string
525
     */
526 1
    protected function sanitizeCommand($command)
527
    {
528 1
        return str_replace(' ', '', $this->ucwordsUnicode(str_replace('_', ' ', $command)));
529
    }
530
531
    /**
532
     * Enable a single Admin account
533
     *
534
     * @param integer $admin_id Single admin id
535
     *
536
     * @return Telegram
537
     */
538 1
    public function enableAdmin($admin_id)
539
    {
540 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...
541 1
            TelegramLog::error('Invalid value "%s" for admin.', $admin_id);
542 1
        } elseif (!in_array($admin_id, $this->admins_list, true)) {
543 1
            $this->admins_list[] = $admin_id;
544
        }
545
546 1
        return $this;
547
    }
548
549
    /**
550
     * Enable a list of Admin Accounts
551
     *
552
     * @param array $admin_ids List of admin ids
553
     *
554
     * @return Telegram
555
     */
556 1
    public function enableAdmins(array $admin_ids)
557
    {
558 1
        foreach ($admin_ids as $admin_id) {
559 1
            $this->enableAdmin($admin_id);
560
        }
561
562 1
        return $this;
563
    }
564
565
    /**
566
     * Get list of admins
567
     *
568
     * @return array
569
     */
570 1
    public function getAdminList()
571
    {
572 1
        return $this->admins_list;
573
    }
574
575
    /**
576
     * Check if the passed user is an admin
577
     *
578
     * If no user id is passed, the current update is checked for a valid message sender.
579
     *
580
     * @param int|null $user_id
581
     *
582
     * @return bool
583
     */
584 1
    public function isAdmin($user_id = null)
585
    {
586 1
        if ($user_id === null && $this->update !== null) {
587
            //Try to figure out if the user is an admin
588
            $update_methods = [
589
                'getMessage',
590
                'getEditedMessage',
591
                'getChannelPost',
592
                'getEditedChannelPost',
593
                'getInlineQuery',
594
                'getChosenInlineResult',
595
                'getCallbackQuery',
596
            ];
597
            foreach ($update_methods as $update_method) {
598
                $object = call_user_func([$this->update, $update_method]);
599
                if ($object !== null && $from = $object->getFrom()) {
600
                    $user_id = $from->getId();
601
                    break;
602
                }
603
            }
604
        }
605
606 1
        return ($user_id === null) ? false : in_array($user_id, $this->admins_list, true);
607
    }
608
609
    /**
610
     * Check if user required the db connection
611
     *
612
     * @return bool
613
     */
614
    public function isDbEnabled()
615
    {
616
        if ($this->mysql_enabled) {
617
            return true;
618
        } else {
619
            return false;
620
        }
621
    }
622
623
    /**
624
     * Add a single custom commands path
625
     *
626
     * @param string $path   Custom commands path to add
627
     * @param bool   $before If the path should be prepended or appended to the list
628
     *
629
     * @return Telegram
630
     */
631 30
    public function addCommandsPath($path, $before = true)
632
    {
633 30
        if (!is_dir($path)) {
634 1
            TelegramLog::error('Commands path "%s" does not exist.', $path);
635 30
        } elseif (!in_array($path, $this->commands_paths, true)) {
636 30
            if ($before) {
637 30
                array_unshift($this->commands_paths, $path);
638
            } else {
639
                $this->commands_paths[] = $path;
640
            }
641
        }
642
643 30
        return $this;
644
    }
645
646
    /**
647
     * Add multiple custom commands paths
648
     *
649
     * @param array $paths  Custom commands paths to add
650
     * @param bool  $before If the paths should be prepended or appended to the list
651
     *
652
     * @return Telegram
653
     */
654 1
    public function addCommandsPaths(array $paths, $before = true)
655
    {
656 1
        foreach ($paths as $path) {
657 1
            $this->addCommandsPath($path, $before);
658
        }
659
660 1
        return $this;
661
    }
662
663
    /**
664
     * Return the list of commands paths
665
     *
666
     * @return array
667
     */
668 1
    public function getCommandsPaths()
669
    {
670 1
        return $this->commands_paths;
671
    }
672
673
    /**
674
     * Set custom upload path
675
     *
676
     * @param string $path Custom upload path
677
     *
678
     * @return Telegram
679
     */
680
    public function setUploadPath($path)
681
    {
682
        $this->upload_path = $path;
683
684
        return $this;
685
    }
686
687
    /**
688
     * Get custom upload path
689
     *
690
     * @return string
691
     */
692
    public function getUploadPath()
693
    {
694
        return $this->upload_path;
695
    }
696
697
    /**
698
     * Set custom download path
699
     *
700
     * @param string $path Custom download path
701
     *
702
     * @return Telegram
703
     */
704
    public function setDownloadPath($path)
705
    {
706
        $this->download_path = $path;
707
708
        return $this;
709
    }
710
711
    /**
712
     * Get custom download path
713
     *
714
     * @return string
715
     */
716
    public function getDownloadPath()
717
    {
718
        return $this->download_path;
719
    }
720
721
    /**
722
     * Set command config
723
     *
724
     * Provide further variables to a particular commands.
725
     * For example you can add the channel name at the command /sendtochannel
726
     * Or you can add the api key for external service.
727
     *
728
     * @param string $command
729
     * @param array  $config
730
     *
731
     * @return Telegram
732
     */
733 14
    public function setCommandConfig($command, array $config)
734
    {
735 14
        $this->commands_config[$command] = $config;
736
737 14
        return $this;
738
    }
739
740
    /**
741
     * Get command config
742
     *
743
     * @param string $command
744
     *
745
     * @return array
746
     */
747 15
    public function getCommandConfig($command)
748
    {
749 15
        return isset($this->commands_config[$command]) ? $this->commands_config[$command] : [];
750
    }
751
752
    /**
753
     * Get API key
754
     *
755
     * @return string
756
     */
757 1
    public function getApiKey()
758
    {
759 1
        return $this->api_key;
760
    }
761
762
    /**
763
     * Get Bot name
764
     *
765
     * @return string
766
     */
767 1
    public function getBotUsername()
768
    {
769 1
        return $this->bot_username;
770
    }
771
772
    /**
773
     * Get Bot Id
774
     *
775
     * @return string
776
     */
777
    public function getBotId()
778
    {
779
        return $this->bot_id;
780
    }
781
782
    /**
783
     * Get Version
784
     *
785
     * @return string
786
     */
787
    public function getVersion()
788
    {
789
        return $this->version;
790
    }
791
792
    /**
793
     * Set Webhook for bot
794
     *
795
     * @param string $url
796
     * @param array  $data Optional parameters.
797
     *
798
     * @return ServerResponse
799
     * @throws TelegramException
800
     */
801
    public function setWebhook($url, array $data = [])
802
    {
803
        if (empty($url)) {
804
            throw new TelegramException('Hook url is empty!');
805
        }
806
807
        $data        = array_intersect_key($data, array_flip([
808
            'certificate',
809
            'max_connections',
810
            'allowed_updates',
811
        ]));
812
        $data['url'] = $url;
813
814
        // If the certificate is passed as a path, encode and add the file to the data array.
815
        if (!empty($data['certificate']) && is_string($data['certificate'])) {
816
            $data['certificate'] = Request::encodeFile($data['certificate']);
817
        }
818
819
        $result = Request::setWebhook($data);
820
821
        if (!$result->isOk()) {
822
            throw new TelegramException(
823
                'Webhook was not set! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
824
            );
825
        }
826
827
        return $result;
828
    }
829
830
    /**
831
     * Delete any assigned webhook
832
     *
833
     * @return mixed
834
     * @throws TelegramException
835
     */
836
    public function deleteWebhook()
837
    {
838
        $result = Request::deleteWebhook();
839
840
        if (!$result->isOk()) {
841
            throw new TelegramException(
842
                'Webhook was not deleted! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
843
            );
844
        }
845
846
        return $result;
847
    }
848
849
    /**
850
     * Replace function `ucwords` for UTF-8 characters in the class definition and commands
851
     *
852
     * @param string $str
853
     * @param string $encoding (default = 'UTF-8')
854
     *
855
     * @return string
856
     */
857 1
    protected function ucwordsUnicode($str, $encoding = 'UTF-8')
858
    {
859 1
        return mb_convert_case($str, MB_CASE_TITLE, $encoding);
860
    }
861
862
    /**
863
     * Replace function `ucfirst` for UTF-8 characters in the class definition and commands
864
     *
865
     * @param string $str
866
     * @param string $encoding (default = 'UTF-8')
867
     *
868
     * @return string
869
     */
870 1
    protected function ucfirstUnicode($str, $encoding = 'UTF-8')
871
    {
872 1
        return mb_strtoupper(mb_substr($str, 0, 1, $encoding), $encoding)
873 1
               . mb_strtolower(mb_substr($str, 1, mb_strlen($str), $encoding), $encoding);
874
    }
875
876
    /**
877
     * Enable requests limiter
878
     *
879
     * @param array $options
880
     *
881
     * @return Telegram
882
     * @throws TelegramException
883
     */
884
    public function enableLimiter(array $options = [])
885
    {
886
        Request::setLimiter(true, $options);
887
888
        return $this;
889
    }
890
891
    /**
892
     * Run provided commands
893
     *
894
     * @param array $commands
895
     *
896
     * @throws TelegramException
897
     */
898
    public function runCommands($commands)
899
    {
900
        if (!is_array($commands) || empty($commands)) {
0 ignored issues
show
introduced by
The condition is_array($commands) is always true.
Loading history...
901
            throw new TelegramException('No command(s) provided!');
902
        }
903
904
        $this->run_commands = true;
905
906
        $result = Request::getMe();
907
908
        if ($result->isOk()) {
909
            $result = $result->getResult();
910
911
            $bot_id       = $result->getId();
912
            $bot_name     = $result->getFirstName();
913
            $bot_username = $result->getUsername();
914
        } else {
915
            $bot_id       = $this->getBotId();
916
            $bot_name     = $this->getBotUsername();
917
            $bot_username = $this->getBotUsername();
918
        }
919
920
921
        $this->enableAdmin($bot_id);    // Give bot access to admin commands
922
        $this->getCommandsList();       // Load full commands list
923
924
        foreach ($commands as $command) {
925
            $this->update = new Update(
926
                [
927
                    'update_id' => 0,
928
                    'message'   => [
929
                        'message_id' => 0,
930
                        'from'       => [
931
                            'id'         => $bot_id,
932
                            'first_name' => $bot_name,
933
                            'username'   => $bot_username,
934
                        ],
935
                        'date'       => time(),
936
                        'chat'       => [
937
                            'id'   => $bot_id,
938
                            'type' => 'private',
939
                        ],
940
                        'text'       => $command,
941
                    ],
942
                ]
943
            );
944
945
            $this->executeCommand($this->update->getMessage()->getCommand());
946
        }
947
    }
948
949
    /**
950
     * Is this session initiated by runCommands()
951
     *
952
     * @return bool
953
     */
954
    public function isRunCommands()
955
    {
956
        return $this->run_commands;
957
    }
958
959
    /**
960
     * Switch to enable running getUpdates without a database
961
     *
962
     * @param bool $enable
963
     */
964
    public function useGetUpdatesWithoutDatabase($enable = true)
965
    {
966
        $this->getupdates_without_database = $enable;
967
    }
968
969
    /**
970
     * Return last update id
971
     *
972
     * @return int
973
     */
974
    public function getLastUpdateId()
975
    {
976
        return $this->last_update_id;
977
    }
978
}
979