Completed
Push — feature/database-migrations ( b550b6 )
by Avtandil
02:27
created

Telegram   F

Complexity

Total Complexity 104

Size/Duplication

Total Lines 970
Duplicated Lines 2.68 %

Coupling/Cohesion

Components 3
Dependencies 9

Test Coverage

Coverage 32.7%

Importance

Changes 0
Metric Value
dl 26
loc 970
ccs 86
cts 263
cp 0.327
rs 1.6299
c 0
b 0
f 0
wmc 104
lcom 3
cbo 9

42 Methods

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

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $options is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
889
    {
890
        trigger_error('Longman\TelegramBot\Telegram::enableBotan is deprecated and will be removed in future release.', E_USER_DEPRECATED);
891
892
        return $this;
893
    }
894
895
    /**
896
     * Enable requests limiter
897
     *
898
     * @param  array $options
899
     *
900
     * @return \Longman\TelegramBot\Telegram
901
     */
902
    public function enableLimiter(array $options = [])
903
    {
904
        Request::setLimiter(true, $options);
905
906
        return $this;
907
    }
908
909
    /**
910
     * Run provided commands
911
     *
912
     * @param array $commands
913
     *
914
     * @throws TelegramException
915
     */
916
    public function runCommands($commands)
917
    {
918
        if (!is_array($commands) || empty($commands)) {
919
            throw new TelegramException('No command(s) provided!');
920
        }
921
922
        $this->run_commands  = true;
923
924
        $result = Request::getMe();
925
926
        if ($result->isOk()) {
927
            $result = $result->getResult();
928
929
            $bot_id       = $result->getId();
930
            $bot_name     = $result->getFirstName();
931
            $bot_username = $result->getUsername();
932
        } else {
933
            $bot_id       = $this->getBotId();
934
            $bot_name     = $this->getBotUsername();
935
            $bot_username = $this->getBotUsername();
936
        }
937
938
939
        $this->enableAdmin($bot_id);    // Give bot access to admin commands
940
        $this->getCommandsList();       // Load full commands list
941
942
        foreach ($commands as $command) {
943
            $this->update = new Update(
944
                [
945
                    'update_id' => 0,
946
                    'message'   => [
947
                        'message_id' => 0,
948
                        'from'       => [
949
                            'id'         => $bot_id,
950
                            'first_name' => $bot_name,
951
                            'username'   => $bot_username,
952
                        ],
953
                        'date'       => time(),
954
                        'chat'       => [
955
                            'id'   => $bot_id,
956
                            'type' => 'private',
957
                        ],
958
                        'text'       => $command,
959
                    ],
960
                ]
961
            );
962
963
            $this->executeCommand($this->update->getMessage()->getCommand());
964
        }
965
    }
966
967
    /**
968
     * Is this session initiated by runCommands()
969
     *
970
     * @return bool
971
     */
972
    public function isRunCommands()
973
    {
974
        return $this->run_commands;
975
    }
976
977
    /**
978
     * Switch to enable running getUpdates without a database
979
     *
980
     * @param bool $enable
981
     */
982
    public function useGetUpdatesWithoutDatabase($enable = true)
983
    {
984
        $this->getupdates_without_database = $enable;
985
    }
986
987
    /**
988
     * Return last update id
989
     *
990
     * @return int
991
     */
992
    public function getLastUpdateId()
993
    {
994
        return $this->last_update_id;
995
    }
996
}
997