Completed
Push — develop ( 6c3e46...6f27de )
by Armando
06:09
created

Telegram   D

Complexity

Total Complexity 93

Size/Duplication

Total Lines 935
Duplicated Lines 2.78 %

Coupling/Cohesion

Components 3
Dependencies 9

Test Coverage

Coverage 38.67%

Importance

Changes 0
Metric Value
wmc 93
lcom 3
cbo 9
dl 26
loc 935
ccs 94
cts 243
cp 0.3867
rs 4.4444
c 0
b 0
f 0

42 Methods

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