Completed
Push — master ( 773c7d...54823d )
by Armando
03:30 queued 01:45
created

Telegram   D

Complexity

Total Complexity 95

Size/Duplication

Total Lines 937
Duplicated Lines 2.77 %

Coupling/Cohesion

Components 3
Dependencies 9

Test Coverage

Coverage 34.79%

Importance

Changes 0
Metric Value
wmc 95
lcom 3
cbo 9
dl 26
loc 937
ccs 87
cts 250
cp 0.3479
rs 4.4444
c 0
b 0
f 0

40 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 21 4
A enableMySql() 8 8 1
A enableExternalMySql() 8 8 1
A getCommandObject() 0 15 4
A setCustomInput() 0 6 1
A getCustomInput() 0 4 1
A getLastCommandResponse() 0 4 1
C handleGetUpdates() 0 46 7
B handle() 0 23 5
A getCommandFromType() 0 4 1
B getCommandsList() 0 37 6
B processUpdate() 0 49 5
B executeCommand() 0 31 6
A sanitizeCommand() 0 4 1
A enableAdmin() 0 10 4
A enableAdmins() 0 8 2
A getAdminList() 0 4 1
C isAdmin() 0 24 7
A isDbEnabled() 0 8 2
A addCommandsPath() 0 14 4
A addCommandsPaths() 0 8 2
A getCommandsPaths() 0 4 1
A setUploadPath() 0 6 1
A getUploadPath() 0 4 1
A setDownloadPath() 0 6 1
A getDownloadPath() 0 4 1
A setCommandConfig() 0 6 1
A getCommandConfig() 0 4 2
A getApiKey() 0 4 1
A getBotUsername() 0 4 1
A getBotId() 0 4 1
A getVersion() 0 4 1
B setWebhook() 5 28 5
A deleteWebhook() 5 12 2
A ucwordsUnicode() 0 4 1
A ucfirstUnicode() 0 6 1
A enableBotan() 0 7 1
A enableLimiter() 0 6 1
B runCommands() 0 51 5
A isRunCommands() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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
define('BASE_PATH', __DIR__);
14 1
define('BASE_COMMANDS_PATH', 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.50.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 \Longman\TelegramBot\Entities\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 \Longman\TelegramBot\Entities\ServerResponse
123
     */
124
    protected $last_command_response;
125
126
    /**
127
     * Botan.io integration
128
     *
129
     * @var boolean
130
     */
131
    protected $botan_enabled = false;
132
133
    /**
134
     * Check if runCommands() is running in this session
135
     *
136
     * @var boolean
137
     */
138
    protected $run_commands = false;
139
140
    /**
141
     * Telegram constructor.
142
     *
143
     * @param string $api_key
144
     * @param string $bot_username
145
     *
146
     * @throws \Longman\TelegramBot\Exception\TelegramException
147
     */
148 30
    public function __construct($api_key, $bot_username = '')
149
    {
150 30
        if (empty($api_key)) {
151 1
            throw new TelegramException('API KEY not defined!');
152
        }
153 30
        preg_match('/(\d+)\:[\w\-]+/', $api_key, $matches);
154 30
        if (!isset($matches[1])) {
155 1
            throw new TelegramException('Invalid API KEY defined!');
156
        }
157 30
        $this->bot_id  = $matches[1];
158 30
        $this->api_key = $api_key;
159
160 30
        if (!empty($bot_username)) {
161 30
            $this->bot_username = $bot_username;
162
        }
163
164
        //Add default system commands path
165 30
        $this->addCommandsPath(BASE_COMMANDS_PATH . '/SystemCommands');
166
167 30
        Request::initialize($this);
168 30
    }
169
170
    /**
171
     * Initialize Database connection
172
     *
173
     * @param array  $credential
174
     * @param string $table_prefix
175
     * @param string $encoding
176
     *
177
     * @return \Longman\TelegramBot\Telegram
178
     * @throws \Longman\TelegramBot\Exception\TelegramException
179
     */
180 9 View Code Duplication
    public function enableMySql(array $credential, $table_prefix = null, $encoding = 'utf8mb4')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
181
    {
182 9
        $this->pdo = DB::initialize($credential, $this, $table_prefix, $encoding);
183 9
        ConversationDB::initializeConversation();
184 9
        $this->mysql_enabled = true;
185
186 9
        return $this;
187
    }
188
189
    /**
190
     * Initialize Database external connection
191
     *
192
     * @param PDO    $external_pdo_connection PDO database object
193
     * @param string $table_prefix
194
     *
195
     * @return \Longman\TelegramBot\Telegram
196
     * @throws \Longman\TelegramBot\Exception\TelegramException
197
     */
198 View Code Duplication
    public function enableExternalMySql($external_pdo_connection, $table_prefix = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
199
    {
200
        $this->pdo = DB::externalInitialize($external_pdo_connection, $this, $table_prefix);
201
        ConversationDB::initializeConversation();
202
        $this->mysql_enabled = true;
203
204
        return $this;
205
    }
206
207
    /**
208
     * Get commands list
209
     *
210
     * @return array $commands
211
     * @throws \Longman\TelegramBot\Exception\TelegramException
212
     */
213 1
    public function getCommandsList()
214
    {
215 1
        $commands = [];
216
217 1
        foreach ($this->commands_paths as $path) {
218
            try {
219
                //Get all "*Command.php" files
220 1
                $files = new RegexIterator(
221 1
                    new RecursiveIteratorIterator(
222 1
                        new RecursiveDirectoryIterator($path)
223
                    ),
224 1
                    '/^.+Command.php$/'
225
                );
226
227 1
                foreach ($files as $file) {
228
                    //Remove "Command.php" from filename
229 1
                    $command      = $this->sanitizeCommand(substr($file->getFilename(), 0, -11));
230 1
                    $command_name = strtolower($command);
231
232 1
                    if (array_key_exists($command_name, $commands)) {
233
                        continue;
234
                    }
235
236 1
                    require_once $file->getPathname();
237
238 1
                    $command_obj = $this->getCommandObject($command);
239 1
                    if ($command_obj instanceof Command) {
240 1
                        $commands[$command_name] = $command_obj;
241
                    }
242
                }
243
            } catch (Exception $e) {
244 1
                throw new TelegramException('Error getting commands from path: ' . $path);
245
            }
246
        }
247
248 1
        return $commands;
249
    }
250
251
    /**
252
     * Get an object instance of the passed command
253
     *
254
     * @param string $command
255
     *
256
     * @return \Longman\TelegramBot\Commands\Command|null
257
     */
258 1
    public function getCommandObject($command)
259
    {
260 1
        $which = ['System'];
261 1
        $this->isAdmin() && $which[] = 'Admin';
262 1
        $which[] = 'User';
263
264 1
        foreach ($which as $auth) {
265 1
            $command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands\\' . $this->ucfirstUnicode($command) . 'Command';
266 1
            if (class_exists($command_namespace)) {
267 1
                return new $command_namespace($this, $this->update);
268
            }
269
        }
270
271
        return null;
272
    }
273
274
    /**
275
     * Set custom input string for debug purposes
276
     *
277
     * @param string $input (json format)
278
     *
279
     * @return \Longman\TelegramBot\Telegram
280
     */
281
    public function setCustomInput($input)
282
    {
283
        $this->input = $input;
284
285
        return $this;
286
    }
287
288
    /**
289
     * Get custom input string for debug purposes
290
     *
291
     * @return string
292
     */
293
    public function getCustomInput()
294
    {
295
        return $this->input;
296
    }
297
298
    /**
299
     * Get the ServerResponse of the last Command execution
300
     *
301
     * @return \Longman\TelegramBot\Entities\ServerResponse
302
     */
303
    public function getLastCommandResponse()
304
    {
305
        return $this->last_command_response;
306
    }
307
308
    /**
309
     * Handle getUpdates method
310
     *
311
     * @param int|null $limit
312
     * @param int|null $timeout
313
     *
314
     * @return \Longman\TelegramBot\Entities\ServerResponse
315
     * @throws \Longman\TelegramBot\Exception\TelegramException
316
     */
317
    public function handleGetUpdates($limit = null, $timeout = null)
318
    {
319
        if (empty($this->bot_username)) {
320
            throw new TelegramException('Bot Username is not defined!');
321
        }
322
323
        if (!DB::isDbConnected()) {
324
            return new ServerResponse(
325
                [
326
                    'ok'          => false,
327
                    'description' => 'getUpdates needs MySQL connection!',
328
                ],
329
                $this->bot_username
330
            );
331
        }
332
333
        //Take custom input into account.
334
        if ($custom_input = $this->getCustomInput()) {
335
            $response = new ServerResponse(json_decode($custom_input, true), $this->bot_username);
336
        } else {
337
            //DB Query
338
            $last_update = DB::selectTelegramUpdate(1);
339
            $last_update = reset($last_update);
340
341
            //As explained in the telegram bot api documentation
342
            $offset = isset($last_update['id']) ? $last_update['id'] + 1 : null;
343
344
            $response = Request::getUpdates(
345
                [
346
                    'offset'  => $offset,
347
                    'limit'   => $limit,
348
                    'timeout' => $timeout,
349
                ]
350
            );
351
        }
352
353
        if ($response->isOk()) {
354
            //Process all updates
355
            /** @var Update $result */
356
            foreach ((array) $response->getResult() as $result) {
357
                $this->processUpdate($result);
358
            }
359
        }
360
361
        return $response;
362
    }
363
364
    /**
365
     * Handle bot request from webhook
366
     *
367
     * @return bool
368
     *
369
     * @throws \Longman\TelegramBot\Exception\TelegramException
370
     */
371
    public function handle()
372
    {
373
        if (empty($this->bot_username)) {
374
            throw new TelegramException('Bot Username is not defined!');
375
        }
376
377
        $this->input = Request::getInput();
378
379
        if (empty($this->input)) {
380
            throw new TelegramException('Input is empty!');
381
        }
382
383
        $post = json_decode($this->input, true);
384
        if (empty($post)) {
385
            throw new TelegramException('Invalid JSON!');
386
        }
387
388
        if ($response = $this->processUpdate(new Update($post, $this->bot_username))) {
389
            return $response->isOk();
390
        }
391
392
        return false;
393
    }
394
395
    /**
396
     * Get the command name from the command type
397
     *
398
     * @param string $type
399
     *
400
     * @return string
401
     */
402
    protected function getCommandFromType($type)
403
    {
404
        return $this->ucfirstUnicode(str_replace('_', '', $type));
405
    }
406
407
    /**
408
     * Process bot Update request
409
     *
410
     * @param \Longman\TelegramBot\Entities\Update $update
411
     *
412
     * @return \Longman\TelegramBot\Entities\ServerResponse
413
     * @throws \Longman\TelegramBot\Exception\TelegramException
414
     */
415
    public function processUpdate(Update $update)
416
    {
417
        $this->update = $update;
418
419
        //If all else fails, it's a generic message.
420
        $command = 'genericmessage';
421
422
        $update_type = $this->update->getUpdateType();
423
        if ($update_type === 'message') {
424
            $message = $this->update->getMessage();
425
426
            //Load admin commands
427
            if ($this->isAdmin()) {
428
                $this->addCommandsPath(BASE_COMMANDS_PATH . '/AdminCommands', false);
429
            }
430
431
            $type = $message->getType();
432
            if ($type === 'command') {
433
                $command = $message->getCommand();
434
            } elseif (in_array($type, [
435
                'new_chat_members',
436
                'left_chat_member',
437
                'new_chat_title',
438
                'new_chat_photo',
439
                'delete_chat_photo',
440
                'group_chat_created',
441
                'supergroup_chat_created',
442
                'channel_chat_created',
443
                'migrate_to_chat_id',
444
                'migrate_from_chat_id',
445
                'pinned_message',
446
                'invoice',
447
                'successful_payment',
448
            ], true)
449
            ) {
450
                $command = $this->getCommandFromType($type);
451
            }
452
        } else {
453
            $command = $this->getCommandFromType($update_type);
454
        }
455
456
        //Make sure we have an up-to-date command list
457
        //This is necessary to "require" all the necessary command files!
458
        $this->getCommandsList();
459
460
        DB::insertRequest($this->update);
461
462
        return $this->executeCommand($command);
463
    }
464
465
    /**
466
     * Execute /command
467
     *
468
     * @param string $command
469
     *
470
     * @return mixed
471
     * @throws \Longman\TelegramBot\Exception\TelegramException
472
     */
473
    public function executeCommand($command)
474
    {
475
        $command     = strtolower($command);
476
        $command_obj = $this->getCommandObject($command);
477
478
        if (!$command_obj || !$command_obj->isEnabled()) {
479
            //Failsafe in case the Generic command can't be found
480
            if ($command === 'generic') {
481
                throw new TelegramException('Generic command missing!');
482
            }
483
484
            //Handle a generic command or non existing one
485
            $this->last_command_response = $this->executeCommand('generic');
486
        } else {
487
            //Botan.io integration, make sure only the actual command user executed is reported
488
            if ($this->botan_enabled) {
489
                Botan::lock($command);
490
            }
491
492
            //execute() method is executed after preExecute()
493
            //This is to prevent executing a DB query without a valid connection
494
            $this->last_command_response = $command_obj->preExecute();
495
496
            //Botan.io integration, send report after executing the command
497
            if ($this->botan_enabled) {
498
                Botan::track($this->update, $command);
499
            }
500
        }
501
502
        return $this->last_command_response;
503
    }
504
505
    /**
506
     * Sanitize Command
507
     *
508
     * @param string $command
509
     *
510
     * @return string
511
     */
512 1
    protected function sanitizeCommand($command)
513
    {
514 1
        return str_replace(' ', '', $this->ucwordsUnicode(str_replace('_', ' ', $command)));
515
    }
516
517
    /**
518
     * Enable a single Admin account
519
     *
520
     * @param integer $admin_id Single admin id
521
     *
522
     * @return \Longman\TelegramBot\Telegram
523
     */
524 1
    public function enableAdmin($admin_id)
525
    {
526 1
        if (!is_int($admin_id) || $admin_id <= 0) {
527 1
            TelegramLog::error('Invalid value "%s" for admin.', $admin_id);
528 1
        } elseif (!in_array($admin_id, $this->admins_list, true)) {
529 1
            $this->admins_list[] = $admin_id;
530
        }
531
532 1
        return $this;
533
    }
534
535
    /**
536
     * Enable a list of Admin Accounts
537
     *
538
     * @param array $admin_ids List of admin ids
539
     *
540
     * @return \Longman\TelegramBot\Telegram
541
     */
542 1
    public function enableAdmins(array $admin_ids)
543
    {
544 1
        foreach ($admin_ids as $admin_id) {
545 1
            $this->enableAdmin($admin_id);
546
        }
547
548 1
        return $this;
549
    }
550
551
    /**
552
     * Get list of admins
553
     *
554
     * @return array
555
     */
556 1
    public function getAdminList()
557
    {
558 1
        return $this->admins_list;
559
    }
560
561
    /**
562
     * Check if the passed user is an admin
563
     *
564
     * If no user id is passed, the current update is checked for a valid message sender.
565
     *
566
     * @param int|null $user_id
567
     *
568
     * @return bool
569
     */
570 1
    public function isAdmin($user_id = null)
571
    {
572 1
        if ($user_id === null && $this->update !== null) {
573
            //Try to figure out if the user is an admin
574
            $update_methods = [
575
                'getMessage',
576
                'getEditedMessage',
577
                'getChannelPost',
578
                'getEditedChannelPost',
579
                'getInlineQuery',
580
                'getChosenInlineResult',
581
                'getCallbackQuery',
582
            ];
583
            foreach ($update_methods as $update_method) {
584
                $object = call_user_func([$this->update, $update_method]);
585
                if ($object !== null && $from = $object->getFrom()) {
586
                    $user_id = $from->getId();
587
                    break;
588
                }
589
            }
590
        }
591
592 1
        return ($user_id === null) ? false : in_array($user_id, $this->admins_list, true);
593
    }
594
595
    /**
596
     * Check if user required the db connection
597
     *
598
     * @return bool
599
     */
600
    public function isDbEnabled()
601
    {
602
        if ($this->mysql_enabled) {
603
            return true;
604
        } else {
605
            return false;
606
        }
607
    }
608
609
    /**
610
     * Add a single custom commands path
611
     *
612
     * @param string $path   Custom commands path to add
613
     * @param bool   $before If the path should be prepended or appended to the list
614
     *
615
     * @return \Longman\TelegramBot\Telegram
616
     */
617 30
    public function addCommandsPath($path, $before = true)
618
    {
619 30
        if (!is_dir($path)) {
620 1
            TelegramLog::error('Commands path "%s" does not exist.', $path);
621 30
        } elseif (!in_array($path, $this->commands_paths, true)) {
622 30
            if ($before) {
623 30
                array_unshift($this->commands_paths, $path);
624
            } else {
625
                $this->commands_paths[] = $path;
626
            }
627
        }
628
629 30
        return $this;
630
    }
631
632
    /**
633
     * Add multiple custom commands paths
634
     *
635
     * @param array $paths  Custom commands paths to add
636
     * @param bool  $before If the paths should be prepended or appended to the list
637
     *
638
     * @return \Longman\TelegramBot\Telegram
639
     */
640 1
    public function addCommandsPaths(array $paths, $before = true)
641
    {
642 1
        foreach ($paths as $path) {
643 1
            $this->addCommandsPath($path, $before);
644
        }
645
646 1
        return $this;
647
    }
648
649
    /**
650
     * Return the list of commands paths
651
     *
652
     * @return array
653
     */
654 1
    public function getCommandsPaths()
655
    {
656 1
        return $this->commands_paths;
657
    }
658
659
    /**
660
     * Set custom upload path
661
     *
662
     * @param string $path Custom upload path
663
     *
664
     * @return \Longman\TelegramBot\Telegram
665
     */
666
    public function setUploadPath($path)
667
    {
668
        $this->upload_path = $path;
669
670
        return $this;
671
    }
672
673
    /**
674
     * Get custom upload path
675
     *
676
     * @return string
677
     */
678
    public function getUploadPath()
679
    {
680
        return $this->upload_path;
681
    }
682
683
    /**
684
     * Set custom download path
685
     *
686
     * @param string $path Custom download path
687
     *
688
     * @return \Longman\TelegramBot\Telegram
689
     */
690
    public function setDownloadPath($path)
691
    {
692
        $this->download_path = $path;
693
694
        return $this;
695
    }
696
697
    /**
698
     * Get custom download path
699
     *
700
     * @return string
701
     */
702
    public function getDownloadPath()
703
    {
704
        return $this->download_path;
705
    }
706
707
    /**
708
     * Set command config
709
     *
710
     * Provide further variables to a particular commands.
711
     * For example you can add the channel name at the command /sendtochannel
712
     * Or you can add the api key for external service.
713
     *
714
     * @param string $command
715
     * @param array  $config
716
     *
717
     * @return \Longman\TelegramBot\Telegram
718
     */
719 14
    public function setCommandConfig($command, array $config)
720
    {
721 14
        $this->commands_config[$command] = $config;
722
723 14
        return $this;
724
    }
725
726
    /**
727
     * Get command config
728
     *
729
     * @param string $command
730
     *
731
     * @return array
732
     */
733 15
    public function getCommandConfig($command)
734
    {
735 15
        return isset($this->commands_config[$command]) ? $this->commands_config[$command] : [];
736
    }
737
738
    /**
739
     * Get API key
740
     *
741
     * @return string
742
     */
743 1
    public function getApiKey()
744
    {
745 1
        return $this->api_key;
746
    }
747
748
    /**
749
     * Get Bot name
750
     *
751
     * @return string
752
     */
753 1
    public function getBotUsername()
754
    {
755 1
        return $this->bot_username;
756
    }
757
758
    /**
759
     * Get Bot Id
760
     *
761
     * @return string
762
     */
763
    public function getBotId()
764
    {
765
        return $this->bot_id;
766
    }
767
768
    /**
769
     * Get Version
770
     *
771
     * @return string
772
     */
773
    public function getVersion()
774
    {
775
        return $this->version;
776
    }
777
778
    /**
779
     * Set Webhook for bot
780
     *
781
     * @param string $url
782
     * @param array  $data Optional parameters.
783
     *
784
     * @return \Longman\TelegramBot\Entities\ServerResponse
785
     * @throws \Longman\TelegramBot\Exception\TelegramException
786
     */
787
    public function setWebhook($url, array $data = [])
788
    {
789
        if (empty($url)) {
790
            throw new TelegramException('Hook url is empty!');
791
        }
792
793
        $data        = array_intersect_key($data, array_flip([
794
            'certificate',
795
            'max_connections',
796
            'allowed_updates',
797
        ]));
798
        $data['url'] = $url;
799
800
        // If the certificate is passed as a path, encode and add the file to the data array.
801
        if (!empty($data['certificate']) && is_string($data['certificate'])) {
802
            $data['certificate'] = Request::encodeFile($data['certificate']);
803
        }
804
805
        $result = Request::setWebhook($data);
806
807 View Code Duplication
        if (!$result->isOk()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
808
            throw new TelegramException(
809
                'Webhook was not set! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
810
            );
811
        }
812
813
        return $result;
814
    }
815
816
    /**
817
     * Delete any assigned webhook
818
     *
819
     * @return mixed
820
     * @throws \Longman\TelegramBot\Exception\TelegramException
821
     */
822
    public function deleteWebhook()
823
    {
824
        $result = Request::deleteWebhook();
825
826 View Code Duplication
        if (!$result->isOk()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
827
            throw new TelegramException(
828
                'Webhook was not deleted! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
829
            );
830
        }
831
832
        return $result;
833
    }
834
835
    /**
836
     * Replace function `ucwords` for UTF-8 characters in the class definition and commands
837
     *
838
     * @param string $str
839
     * @param string $encoding (default = 'UTF-8')
840
     *
841
     * @return string
842
     */
843 1
    protected function ucwordsUnicode($str, $encoding = 'UTF-8')
844
    {
845 1
        return mb_convert_case($str, MB_CASE_TITLE, $encoding);
846
    }
847
848
    /**
849
     * Replace function `ucfirst` for UTF-8 characters in the class definition and commands
850
     *
851
     * @param string $str
852
     * @param string $encoding (default = 'UTF-8')
853
     *
854
     * @return string
855
     */
856 1
    protected function ucfirstUnicode($str, $encoding = 'UTF-8')
857
    {
858
        return
859 1
            mb_strtoupper(mb_substr($str, 0, 1, $encoding), $encoding)
860 1
            . mb_strtolower(mb_substr($str, 1, mb_strlen($str), $encoding), $encoding);
861
    }
862
863
    /**
864
     * Enable Botan.io integration
865
     *
866
     * @param  string $token
867
     * @param  array  $options
868
     *
869
     * @return \Longman\TelegramBot\Telegram
870
     * @throws \Longman\TelegramBot\Exception\TelegramException
871
     */
872
    public function enableBotan($token, array $options = [])
873
    {
874
        Botan::initializeBotan($token, $options);
875
        $this->botan_enabled = true;
876
877
        return $this;
878
    }
879
880
    /**
881
     * Enable requests limiter
882
     *
883
     * @param  array $options
884
     *
885
     * @return \Longman\TelegramBot\Telegram
886
     */
887
    public function enableLimiter(array $options = [])
888
    {
889
        Request::setLimiter(true, $options);
890
891
        return $this;
892
    }
893
894
    /**
895
     * Run provided commands
896
     *
897
     * @param array $commands
898
     *
899
     * @throws TelegramException
900
     */
901
    public function runCommands($commands)
902
    {
903
        if (!is_array($commands) || empty($commands)) {
904
            throw new TelegramException('No command(s) provided!');
905
        }
906
907
        $this->run_commands  = true;
908
        $this->botan_enabled = false;   // Force disable Botan.io integration, we don't want to track self-executed commands!
909
910
        $result = Request::getMe();
911
912
        if ($result->isOk()) {
913
            $result = $result->getResult();
914
915
            $bot_id       = $result->getId();
916
            $bot_name     = $result->getFirstName();
917
            $bot_username = $result->getUsername();
918
        } else {
919
            $bot_id       = $this->getBotId();
920
            $bot_name     = $this->getBotUsername();
921
            $bot_username = $this->getBotUsername();
922
        }
923
924
925
        $this->enableAdmin($bot_id);    // Give bot access to admin commands
926
        $this->getCommandsList();       // Load full commands list
927
928
        foreach ($commands as $command) {
929
            $this->update = new Update(
930
                [
931
                    'update_id' => 0,
932
                    'message'   => [
933
                        'message_id' => 0,
934
                        'from'       => [
935
                            'id'         => $bot_id,
936
                            'first_name' => $bot_name,
937
                            'username'   => $bot_username,
938
                        ],
939
                        'date'       => time(),
940
                        'chat'       => [
941
                            'id'   => $bot_id,
942
                            'type' => 'private',
943
                        ],
944
                        'text'       => $command,
945
                    ],
946
                ]
947
            );
948
949
            $this->executeCommand($this->update->getMessage()->getCommand());
950
        }
951
    }
952
953
    /**
954
     * Is this session initiated by runCommands()
955
     *
956
     * @return bool
957
     */
958
    public function isRunCommands()
959
    {
960
        return $this->run_commands;
961
    }
962
}
963