Completed
Push — master ( 9d4d02...0bdd7a )
by Armando
06:45
created

Telegram   D

Complexity

Total Complexity 95

Size/Duplication

Total Lines 942
Duplicated Lines 2.76 %

Coupling/Cohesion

Components 3
Dependencies 9

Test Coverage

Coverage 37.8%

Importance

Changes 0
Metric Value
wmc 95
lcom 3
cbo 9
dl 26
loc 942
ccs 93
cts 246
cp 0.378
rs 4.4444
c 0
b 0
f 0

42 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 25 4
A enableMySql() 8 8 1
A enableExternalMySql() 8 8 1
B getCommandsList() 0 37 6
A getCommandObject() 0 15 4
A setCustomInput() 0 6 1
A getCustomInput() 0 4 1
A getLastCommandResponse() 0 4 1
B handleGetUpdates() 0 41 6
B handle() 0 23 5
A getCommandFromType() 0 4 1
B processUpdate() 0 47 6
B executeCommand() 0 30 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 getBotName() 0 5 1
A getBotId() 0 4 1
A getVersion() 0 4 1
A setWebhook() 5 16 3
A unsetWebhook() 0 4 1
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 46 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.43.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
        //Set default download and upload path
165 30
        $this->setDownloadPath(BASE_PATH . '/../Download');
166 30
        $this->setUploadPath(BASE_PATH . '/../Upload');
167
168
        //Add default system commands path
169 30
        $this->addCommandsPath(BASE_COMMANDS_PATH . '/SystemCommands');
170
171 30
        Request::initialize($this);
172 30
    }
173
174
    /**
175
     * Initialize Database connection
176
     *
177
     * @param array  $credential
178
     * @param string $table_prefix
179
     * @param string $encoding
180
     *
181
     * @return \Longman\TelegramBot\Telegram
182
     * @throws \Longman\TelegramBot\Exception\TelegramException
183
     */
184 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...
185
    {
186 9
        $this->pdo = DB::initialize($credential, $this, $table_prefix, $encoding);
187 9
        ConversationDB::initializeConversation();
188 9
        $this->mysql_enabled = true;
189
190 9
        return $this;
191
    }
192
193
    /**
194
     * Initialize Database external connection
195
     *
196
     * @param PDO    $external_pdo_connection PDO database object
197
     * @param string $table_prefix
198
     *
199
     * @return \Longman\TelegramBot\Telegram
200
     * @throws \Longman\TelegramBot\Exception\TelegramException
201
     */
202 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...
203
    {
204
        $this->pdo = DB::externalInitialize($external_pdo_connection, $this, $table_prefix);
205
        ConversationDB::initializeConversation();
206
        $this->mysql_enabled = true;
207
208
        return $this;
209
    }
210
211
    /**
212
     * Get commands list
213
     *
214
     * @return array $commands
215
     * @throws \Longman\TelegramBot\Exception\TelegramException
216
     */
217 1
    public function getCommandsList()
218
    {
219 1
        $commands = [];
220
221 1
        foreach ($this->commands_paths as $path) {
222
            try {
223
                //Get all "*Command.php" files
224 1
                $files = new RegexIterator(
225 1
                    new RecursiveIteratorIterator(
226 1
                        new RecursiveDirectoryIterator($path)
227
                    ),
228 1
                    '/^.+Command.php$/'
229
                );
230
231 1
                foreach ($files as $file) {
232
                    //Remove "Command.php" from filename
233 1
                    $command      = $this->sanitizeCommand(substr($file->getFilename(), 0, -11));
234 1
                    $command_name = strtolower($command);
235
236 1
                    if (array_key_exists($command_name, $commands)) {
237
                        continue;
238
                    }
239
240 1
                    require_once $file->getPathname();
241
242 1
                    $command_obj = $this->getCommandObject($command);
243 1
                    if ($command_obj instanceof Command) {
244 1
                        $commands[$command_name] = $command_obj;
245
                    }
246
                }
247
            } catch (Exception $e) {
248
                throw new TelegramException('Error getting commands from path: ' . $path);
249
            }
250
        }
251
252 1
        return $commands;
253
    }
254
255
    /**
256
     * Get an object instance of the passed command
257
     *
258
     * @param string $command
259
     *
260
     * @return \Longman\TelegramBot\Commands\Command|null
261
     */
262 1
    public function getCommandObject($command)
263
    {
264 1
        $which = ['System'];
265 1
        $this->isAdmin() && $which[] = 'Admin';
266 1
        $which[] = 'User';
267
268 1
        foreach ($which as $auth) {
269 1
            $command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands\\' . $this->ucfirstUnicode($command) . 'Command';
270 1
            if (class_exists($command_namespace)) {
271 1
                return new $command_namespace($this, $this->update);
272
            }
273
        }
274
275
        return null;
276
    }
277
278
    /**
279
     * Set custom input string for debug purposes
280
     *
281
     * @param string $input (json format)
282
     *
283
     * @return \Longman\TelegramBot\Telegram
284
     */
285
    public function setCustomInput($input)
286
    {
287
        $this->input = $input;
288
289
        return $this;
290
    }
291
292
    /**
293
     * Get custom input string for debug purposes
294
     *
295
     * @return string
296
     */
297
    public function getCustomInput()
298
    {
299
        return $this->input;
300
    }
301
302
    /**
303
     * Get the ServerResponse of the last Command execution
304
     *
305
     * @return \Longman\TelegramBot\Entities\ServerResponse
306
     */
307
    public function getLastCommandResponse()
308
    {
309
        return $this->last_command_response;
310
    }
311
312
    /**
313
     * Handle getUpdates method
314
     *
315
     * @param int|null $limit
316
     * @param int|null $timeout
317
     *
318
     * @return \Longman\TelegramBot\Entities\ServerResponse
319
     * @throws \Longman\TelegramBot\Exception\TelegramException
320
     */
321
    public function handleGetUpdates($limit = null, $timeout = null)
322
    {
323
        if (empty($this->bot_username)) {
324
            throw new TelegramException('Bot Username is not defined!');
325
        }
326
327
        if (!DB::isDbConnected()) {
328
            return new ServerResponse(
329
                [
330
                    'ok'          => false,
331
                    'description' => 'getUpdates needs MySQL connection!',
332
                ],
333
                $this->bot_username
334
            );
335
        }
336
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
        if ($response->isOk()) {
353
            //Process all updates
354
            /** @var Update $result */
355
            foreach ((array) $response->getResult() as $result) {
356
                $this->processUpdate($result);
357
            }
358
        }
359
360
        return $response;
361
    }
362
363
    /**
364
     * Handle bot request from webhook
365
     *
366
     * @return bool
367
     *
368
     * @throws \Longman\TelegramBot\Exception\TelegramException
369
     */
370
    public function handle()
371
    {
372
        if (empty($this->bot_username)) {
373
            throw new TelegramException('Bot Username is not defined!');
374
        }
375
376
        $this->input = Request::getInput();
377
378
        if (empty($this->input)) {
379
            throw new TelegramException('Input is empty!');
380
        }
381
382
        $post = json_decode($this->input, true);
383
        if (empty($post)) {
384
            throw new TelegramException('Invalid JSON!');
385
        }
386
387
        if ($response = $this->processUpdate(new Update($post, $this->bot_username))) {
388
            return $response->isOk();
389
        }
390
391
        return false;
392
    }
393
394
    /**
395
     * Get the command name from the command type
396
     *
397
     * @param string $type
398
     *
399
     * @return string
400
     */
401
    protected function getCommandFromType($type)
402
    {
403
        return $this->ucfirstUnicode(str_replace('_', '', $type));
404
    }
405
406
    /**
407
     * Process bot Update request
408
     *
409
     * @param \Longman\TelegramBot\Entities\Update $update
410
     *
411
     * @return \Longman\TelegramBot\Entities\ServerResponse
412
     * @throws \Longman\TelegramBot\Exception\TelegramException
413
     */
414
    public function processUpdate(Update $update)
415
    {
416
        $this->update = $update;
417
418
        //If all else fails, it's a generic message.
419
        $command = 'genericmessage';
420
421
        $update_type = $this->update->getUpdateType();
422
        if (in_array($update_type, ['edited_message', 'channel_post', 'edited_channel_post', 'inline_query', 'chosen_inline_result', 'callback_query'], true)) {
423
            $command = $this->getCommandFromType($update_type);
424
        } elseif ($update_type === 'message') {
425
            $message = $this->update->getMessage();
426
427
            //Load admin commands
428
            if ($this->isAdmin()) {
429
                $this->addCommandsPath(BASE_COMMANDS_PATH . '/AdminCommands', false);
430
            }
431
432
            $type = $message->getType();
433
            if ($type === 'command') {
434
                $command = $message->getCommand();
435
            } elseif (in_array($type, [
436
                'channel_chat_created',
437
                'delete_chat_photo',
438
                'group_chat_created',
439
                'left_chat_member',
440
                'migrate_from_chat_id',
441
                'migrate_to_chat_id',
442
                'new_chat_member',
443
                'new_chat_photo',
444
                'new_chat_title',
445
                'pinned_message',
446
                'supergroup_chat_created',
447
            ], true)
448
            ) {
449
                $command = $this->getCommandFromType($type);
450
            }
451
        }
452
453
        //Make sure we have an up-to-date command list
454
        //This is necessary to "require" all the necessary command files!
455
        $this->getCommandsList();
456
457
        DB::insertRequest($this->update);
458
459
        return $this->executeCommand($command);
0 ignored issues
show
Bug introduced by
It seems like $command defined by $message->getCommand() on line 434 can also be of type boolean; however, Longman\TelegramBot\Telegram::executeCommand() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
460
    }
461
462
    /**
463
     * Execute /command
464
     *
465
     * @param string $command
466
     *
467
     * @return mixed
468
     * @throws \Longman\TelegramBot\Exception\TelegramException
469
     */
470
    public function executeCommand($command)
471
    {
472
        $command_obj = $this->getCommandObject($command);
473
474
        if (!$command_obj || !$command_obj->isEnabled()) {
475
            //Failsafe in case the Generic command can't be found
476
            if ($command === 'Generic') {
477
                throw new TelegramException('Generic command missing!');
478
            }
479
480
            //Handle a generic command or non existing one
481
            $this->last_command_response = $this->executeCommand('Generic');
482
        } else {
483
            //Botan.io integration, make sure only the actual command user executed is reported
484
            if ($this->botan_enabled) {
485
                Botan::lock($command);
486
            }
487
488
            //execute() method is executed after preExecute()
489
            //This is to prevent executing a DB query without a valid connection
490
            $this->last_command_response = $command_obj->preExecute();
491
492
            //Botan.io integration, send report after executing the command
493
            if ($this->botan_enabled) {
494
                Botan::track($this->update, $command);
495
            }
496
        }
497
498
        return $this->last_command_response;
499
    }
500
501
    /**
502
     * Sanitize Command
503
     *
504
     * @param string $command
505
     *
506
     * @return string
507
     */
508 1
    protected function sanitizeCommand($command)
509
    {
510 1
        return str_replace(' ', '', $this->ucwordsUnicode(str_replace('_', ' ', $command)));
511
    }
512
513
    /**
514
     * Enable a single Admin account
515
     *
516
     * @param integer $admin_id Single admin id
517
     *
518
     * @return \Longman\TelegramBot\Telegram
519
     */
520 1
    public function enableAdmin($admin_id)
521
    {
522 1
        if (is_int($admin_id) && $admin_id > 0 && !in_array($admin_id, $this->admins_list, true)) {
523 1
            $this->admins_list[] = $admin_id;
524
        } else {
525 1
            TelegramLog::error('Invalid value "%s" for admin.', $admin_id);
526
        }
527
528 1
        return $this;
529
    }
530
531
    /**
532
     * Enable a list of Admin Accounts
533
     *
534
     * @param array $admin_ids List of admin ids
535
     *
536
     * @return \Longman\TelegramBot\Telegram
537
     */
538 1
    public function enableAdmins(array $admin_ids)
539
    {
540 1
        foreach ($admin_ids as $admin_id) {
541 1
            $this->enableAdmin($admin_id);
542
        }
543
544 1
        return $this;
545
    }
546
547
    /**
548
     * Get list of admins
549
     *
550
     * @return array
551
     */
552 1
    public function getAdminList()
553
    {
554 1
        return $this->admins_list;
555
    }
556
557
    /**
558
     * Check if the passed user is an admin
559
     *
560
     * If no user id is passed, the current update is checked for a valid message sender.
561
     *
562
     * @param int|null $user_id
563
     *
564
     * @return bool
565
     */
566 1
    public function isAdmin($user_id = null)
567
    {
568 1
        if ($user_id === null && $this->update !== null) {
569
            //Try to figure out if the user is an admin
570
            $update_methods = [
571
                'getMessage',
572
                'getEditedMessage',
573
                'getChannelPost',
574
                'getEditedChannelPost',
575
                'getInlineQuery',
576
                'getChosenInlineResult',
577
                'getCallbackQuery',
578
            ];
579
            foreach ($update_methods as $update_method) {
580
                $object = call_user_func([$this->update, $update_method]);
581
                if ($object !== null && $from = $object->getFrom()) {
582
                    $user_id = $from->getId();
583
                    break;
584
                }
585
            }
586
        }
587
588 1
        return ($user_id === null) ? false : in_array($user_id, $this->admins_list, true);
589
    }
590
591
    /**
592
     * Check if user required the db connection
593
     *
594
     * @return bool
595
     */
596
    public function isDbEnabled()
597
    {
598
        if ($this->mysql_enabled) {
599
            return true;
600
        } else {
601
            return false;
602
        }
603
    }
604
605
    /**
606
     * Add a single custom commands path
607
     *
608
     * @param string $path   Custom commands path to add
609
     * @param bool   $before If the path should be prepended or appended to the list
610
     *
611
     * @return \Longman\TelegramBot\Telegram
612
     */
613 30
    public function addCommandsPath($path, $before = true)
614
    {
615 30
        if (!is_dir($path)) {
616 1
            TelegramLog::error('Commands path "%s" does not exist.', $path);
617 30
        } elseif (!in_array($path, $this->commands_paths, true)) {
618 30
            if ($before) {
619 30
                array_unshift($this->commands_paths, $path);
620
            } else {
621
                $this->commands_paths[] = $path;
622
            }
623
        }
624
625 30
        return $this;
626
    }
627
628
    /**
629
     * Add multiple custom commands paths
630
     *
631
     * @param array $paths  Custom commands paths to add
632
     * @param bool  $before If the paths should be prepended or appended to the list
633
     *
634
     * @return \Longman\TelegramBot\Telegram
635
     */
636 1
    public function addCommandsPaths(array $paths, $before = true)
637
    {
638 1
        foreach ($paths as $path) {
639 1
            $this->addCommandsPath($path, $before);
640
        }
641
642 1
        return $this;
643
    }
644
645
    /**
646
     * Return the list of commands paths
647
     *
648
     * @return array
649
     */
650 1
    public function getCommandsPaths()
651
    {
652 1
        return $this->commands_paths;
653
    }
654
655
    /**
656
     * Set custom upload path
657
     *
658
     * @param string $path Custom upload path
659
     *
660
     * @return \Longman\TelegramBot\Telegram
661
     */
662 30
    public function setUploadPath($path)
663
    {
664 30
        $this->upload_path = $path;
665
666 30
        return $this;
667
    }
668
669
    /**
670
     * Get custom upload path
671
     *
672
     * @return string
673
     */
674
    public function getUploadPath()
675
    {
676
        return $this->upload_path;
677
    }
678
679
    /**
680
     * Set custom download path
681
     *
682
     * @param string $path Custom download path
683
     *
684
     * @return \Longman\TelegramBot\Telegram
685
     */
686 30
    public function setDownloadPath($path)
687
    {
688 30
        $this->download_path = $path;
689
690 30
        return $this;
691
    }
692
693
    /**
694
     * Get custom download path
695
     *
696
     * @return string
697
     */
698
    public function getDownloadPath()
699
    {
700
        return $this->download_path;
701
    }
702
703
    /**
704
     * Set command config
705
     *
706
     * Provide further variables to a particular commands.
707
     * For example you can add the channel name at the command /sendtochannel
708
     * Or you can add the api key for external service.
709
     *
710
     * @param string $command
711
     * @param array  $config
712
     *
713
     * @return \Longman\TelegramBot\Telegram
714
     */
715 14
    public function setCommandConfig($command, array $config)
716
    {
717 14
        $this->commands_config[$command] = $config;
718
719 14
        return $this;
720
    }
721
722
    /**
723
     * Get command config
724
     *
725
     * @param string $command
726
     *
727
     * @return array
728
     */
729 15
    public function getCommandConfig($command)
730
    {
731 15
        return isset($this->commands_config[$command]) ? $this->commands_config[$command] : [];
732
    }
733
734
    /**
735
     * Get API key
736
     *
737
     * @return string
738
     */
739 1
    public function getApiKey()
740
    {
741 1
        return $this->api_key;
742
    }
743
744
    /**
745
     * Get Bot name
746
     *
747
     * @return string
748
     */
749 1
    public function getBotUsername()
750
    {
751 1
        return $this->bot_username;
752
    }
753
754
    /**
755
     * Get Bot name
756
     *
757
     * @todo: Left for backwards compatibility, remove in the future
758
     *
759
     * @return string
760
     */
761
    public function getBotName()
762
    {
763
        TelegramLog::debug('Usage of deprecated method getBotName() detected, please use getBotUsername() instead!');
764
        return $this->getBotUsername();
765
    }
766
767
    /**
768
     * Get Bot Id
769
     *
770
     * @return string
771
     */
772
    public function getBotId()
773
    {
774
        return $this->bot_id;
775
    }
776
777
    /**
778
     * Get Version
779
     *
780
     * @return string
781
     */
782
    public function getVersion()
783
    {
784
        return $this->version;
785
    }
786
787
    /**
788
     * Set Webhook for bot
789
     *
790
     * @param string $url
791
     * @param array  $data Optional parameters.
792
     *
793
     * @return \Longman\TelegramBot\Entities\ServerResponse
794
     * @throws \Longman\TelegramBot\Exception\TelegramException
795
     */
796
    public function setWebhook($url, array $data = [])
797
    {
798
        if (empty($url)) {
799
            throw new TelegramException('Hook url is empty!');
800
        }
801
802
        $result = Request::setWebhook($url, $data);
803
804 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...
805
            throw new TelegramException(
806
                'Webhook was not set! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
807
            );
808
        }
809
810
        return $result;
811
    }
812
813
    /**
814
     * Deprecated alias for deleteWebhook
815
     *
816
     * This is kept for backwards compatibility!
817
     *
818
     * @return mixed
819
     * @throws \Longman\TelegramBot\Exception\TelegramException
820
     */
821
    public function unsetWebhook()
822
    {
823
        return $this->deleteWebhook();
824
    }
825
826
    /**
827
     * Delete any assigned webhook
828
     *
829
     * @return mixed
830
     * @throws \Longman\TelegramBot\Exception\TelegramException
831
     */
832
    public function deleteWebhook()
833
    {
834
        $result = Request::deleteWebhook();
835
836 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...
837
            throw new TelegramException(
838
                'Webhook was not deleted! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
839
            );
840
        }
841
842
        return $result;
843
    }
844
845
    /**
846
     * Replace function `ucwords` for UTF-8 characters in the class definition and commands
847
     *
848
     * @param string $str
849
     * @param string $encoding (default = 'UTF-8')
850
     *
851
     * @return string
852
     */
853 1
    protected function ucwordsUnicode($str, $encoding = 'UTF-8')
854
    {
855 1
        return mb_convert_case($str, MB_CASE_TITLE, $encoding);
856
    }
857
858
    /**
859
     * Replace function `ucfirst` for UTF-8 characters in the class definition and commands
860
     *
861
     * @param string $str
862
     * @param string $encoding (default = 'UTF-8')
863
     *
864
     * @return string
865
     */
866 1
    protected function ucfirstUnicode($str, $encoding = 'UTF-8')
867
    {
868
        return
869 1
            mb_strtoupper(mb_substr($str, 0, 1, $encoding), $encoding)
870 1
            . mb_strtolower(mb_substr($str, 1, mb_strlen($str), $encoding), $encoding);
871
    }
872
873
    /**
874
     * Enable Botan.io integration
875
     *
876
     * @param  string $token
877
     * @param  array  $options
878
     *
879
     * @return \Longman\TelegramBot\Telegram
880
     * @throws \Longman\TelegramBot\Exception\TelegramException
881
     */
882
    public function enableBotan($token, array $options = [])
883
    {
884
        Botan::initializeBotan($token, $options);
885
        $this->botan_enabled = true;
886
887
        return $this;
888
    }
889
890
    /**
891
     * Enable requests limiter
892
     *
893
     * @param  array  $options
894
     *
895
     * @return \Longman\TelegramBot\Telegram
896
     */
897
    public function enableLimiter(array $options = [])
898
    {
899
        Request::setLimiter(true, $options);
900
901
        return $this;
902
    }
903
904
    /**
905
     * Run provided commands
906
     *
907
     * @param array $commands
908
     *
909
     * @throws TelegramException
910
     */
911
    public function runCommands($commands)
912
    {
913
        if (!is_array($commands) || empty($commands)) {
914
            throw new TelegramException('No command(s) provided!');
915
        }
916
917
        $this->run_commands = true;
918
        $this->botan_enabled = false;   // Force disable Botan.io integration, we don't want to track self-executed commands!
919
920
        $result = Request::getMe()->getResult();
921
922
        if (!$result->getId()) {
923
            throw new TelegramException('Received empty/invalid getMe result!');
924
        }
925
926
        $bot_id       = $result->getId();
927
        $bot_name     = $result->getFirstName();
928
        $bot_username = $result->getUsername();
929
930
        $this->enableAdmin($bot_id);    // Give bot access to admin commands
931
        $this->getCommandsList();       // Load full commands list
932
933
        foreach ($commands as $command) {
934
            $this->update = new Update(
935
                [
936
                    'update_id' => 0,
937
                    'message'   => [
938
                        'message_id' => 0,
939
                        'from'       => [
940
                            'id'         => $bot_id,
941
                            'first_name' => $bot_name,
942
                            'username'   => $bot_username,
943
                        ],
944
                        'date'       => time(),
945
                        'chat'       => [
946
                            'id'         => $bot_id,
947
                            'type'       => 'private',
948
                        ],
949
                        'text'       => $command,
950
                    ],
951
                ]
952
            );
953
954
            $this->executeCommand($this->update->getMessage()->getCommand());
0 ignored issues
show
Bug introduced by
It seems like $this->update->getMessage()->getCommand() targeting Longman\TelegramBot\Entities\Message::getCommand() can also be of type boolean; however, Longman\TelegramBot\Telegram::executeCommand() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
955
        }
956
    }
957
958
    /**
959
     * Is this session initiated by runCommands()
960
     *
961
     * @return bool
962
     */
963
    public function isRunCommands()
964
    {
965
        return $this->run_commands;
966
    }
967
}
968