Passed
Push — master ( 78024d...fb0f34 )
by Armando
02:56
created

Telegram::getCommandObject()   B

Complexity

Conditions 11
Paths 34

Size

Total Lines 40
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 21.3072

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 25
c 1
b 0
f 0
nc 34
nop 2
dl 0
loc 40
ccs 14
cts 25
cp 0.56
crap 21.3072
rs 7.3166

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This file is part of the TelegramBot package.
5
 *
6
 * (c) Avtandil Kikabidze aka LONGMAN <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Longman\TelegramBot;
13
14 1
defined('TB_BASE_PATH') || define('TB_BASE_PATH', __DIR__);
15 1
defined('TB_BASE_COMMANDS_PATH') || define('TB_BASE_COMMANDS_PATH', TB_BASE_PATH . '/Commands');
16
17
use Exception;
18
use Longman\TelegramBot\Commands\AdminCommand;
19
use Longman\TelegramBot\Commands\Command;
20
use Longman\TelegramBot\Commands\SystemCommand;
21
use Longman\TelegramBot\Commands\UserCommand;
22
use Longman\TelegramBot\Entities\ServerResponse;
23
use Longman\TelegramBot\Entities\Update;
24
use Longman\TelegramBot\Exception\TelegramException;
25
use PDO;
26
use RecursiveDirectoryIterator;
27
use RecursiveIteratorIterator;
28
use RegexIterator;
29
30
class Telegram
31
{
32
    /**
33
     * Version
34
     *
35
     * @var string
36
     */
37
    protected $version = '0.63.0';
38
39
    /**
40
     * Telegram API key
41
     *
42
     * @var string
43
     */
44
    protected $api_key = '';
45
46
    /**
47
     * Telegram Bot username
48
     *
49
     * @var string
50
     */
51
    protected $bot_username = '';
52
53
    /**
54
     * Telegram Bot id
55
     *
56
     * @var string
57
     */
58
    protected $bot_id = '';
59
60
    /**
61
     * Raw request data (json) for webhook methods
62
     *
63
     * @var string
64
     */
65
    protected $input;
66
67
    /**
68
     * Custom commands paths
69
     *
70
     * @var array
71
     */
72
    protected $commands_paths = [];
73
74
    /**
75
     * Custom commands objects
76
     *
77
     * @var array
78
     */
79
    protected $commands_objects = [];
80
81
    /**
82
     * Current Update object
83
     *
84
     * @var Update
85
     */
86
    protected $update;
87
88
    /**
89
     * Upload path
90
     *
91
     * @var string
92
     */
93
    protected $upload_path;
94
95
    /**
96
     * Download path
97
     *
98
     * @var string
99
     */
100
    protected $download_path;
101
102
    /**
103
     * MySQL integration
104
     *
105
     * @var bool
106
     */
107
    protected $mysql_enabled = false;
108
109
    /**
110
     * PDO object
111
     *
112
     * @var PDO
113
     */
114
    protected $pdo;
115
116
    /**
117
     * Commands config
118
     *
119
     * @var array
120
     */
121
    protected $commands_config = [];
122
123
    /**
124
     * Admins list
125
     *
126
     * @var array
127
     */
128
    protected $admins_list = [];
129
130
    /**
131
     * ServerResponse of the last Command execution
132
     *
133
     * @var ServerResponse
134
     */
135
    protected $last_command_response;
136
137
    /**
138
     * Check if runCommands() is running in this session
139
     *
140
     * @var bool
141
     */
142
    protected $run_commands = false;
143
144
    /**
145
     * Is running getUpdates without DB enabled
146
     *
147
     * @var bool
148
     */
149
    protected $getupdates_without_database = false;
150
151
    /**
152
     * Last update ID
153
     * Only used when running getUpdates without a database
154
     *
155
     * @var integer
156
     */
157
    protected $last_update_id;
158
159
    /**
160
     * The command to be executed when there's a new message update and nothing more suitable is found
161
     */
162
    const GENERIC_MESSAGE_COMMAND = 'genericmessage';
163
164
    /**
165
     * The command to be executed by default (when no other relevant commands are applicable)
166
     */
167
    const GENERIC_COMMAND = 'generic';
168
169
    /**
170
     * Update filter
171
     * Filter updates
172
     *
173
     * @var callback
174
     */
175
    protected $update_filter;
176
177
    /**
178
     * Telegram constructor.
179
     *
180
     * @param string $api_key
181
     * @param string $bot_username
182
     *
183
     * @throws TelegramException
184
     */
185 30
    public function __construct($api_key, $bot_username = '')
186
    {
187 30
        if (empty($api_key)) {
188 1
            throw new TelegramException('API KEY not defined!');
189
        }
190 30
        preg_match('/(\d+)\:[\w\-]+/', $api_key, $matches);
191 30
        if (!isset($matches[1])) {
192 1
            throw new TelegramException('Invalid API KEY defined!');
193
        }
194 30
        $this->bot_id  = $matches[1];
195 30
        $this->api_key = $api_key;
196
197 30
        if (!empty($bot_username)) {
198 30
            $this->bot_username = $bot_username;
199
        }
200
201
        //Add default system commands path
202 30
        $this->addCommandsPath(TB_BASE_COMMANDS_PATH . '/SystemCommands');
203
204 30
        Request::initialize($this);
205 30
    }
206
207
    /**
208
     * Initialize Database connection
209
     *
210
     * @param array  $credential
211
     * @param string $table_prefix
212
     * @param string $encoding
213
     *
214
     * @return Telegram
215
     * @throws TelegramException
216
     */
217 9
    public function enableMySql(array $credential, $table_prefix = null, $encoding = 'utf8mb4')
218
    {
219 9
        $this->pdo = DB::initialize($credential, $this, $table_prefix, $encoding);
220 9
        ConversationDB::initializeConversation();
221 9
        $this->mysql_enabled = true;
222
223 9
        return $this;
224
    }
225
226
    /**
227
     * Initialize Database external connection
228
     *
229
     * @param PDO    $external_pdo_connection PDO database object
230
     * @param string $table_prefix
231
     *
232
     * @return Telegram
233
     * @throws TelegramException
234
     */
235
    public function enableExternalMySql($external_pdo_connection, $table_prefix = null)
236
    {
237
        $this->pdo = DB::externalInitialize($external_pdo_connection, $this, $table_prefix);
238
        ConversationDB::initializeConversation();
239
        $this->mysql_enabled = true;
240
241
        return $this;
242
    }
243
244
    /**
245
     * Get commands list
246
     *
247
     * @return array $commands
248
     * @throws TelegramException
249
     */
250 1
    public function getCommandsList()
251
    {
252 1
        $commands = [];
253
254 1
        foreach ($this->commands_paths as $path) {
255
            try {
256
                //Get all "*Command.php" files
257 1
                $files = new RegexIterator(
258 1
                    new RecursiveIteratorIterator(
259 1
                        new RecursiveDirectoryIterator($path)
260
                    ),
261 1
                    '/^.+Command.php$/'
262
                );
263
264 1
                foreach ($files as $file) {
265
                    //Remove "Command.php" from filename
266 1
                    $command      = $this->sanitizeCommand(substr($file->getFilename(), 0, -11));
267 1
                    $command_name = mb_strtolower($command);
268
269 1
                    if (array_key_exists($command_name, $commands)) {
270
                        continue;
271
                    }
272
273 1
                    require_once $file->getPathname();
274
275 1
                    $command_obj = $this->getCommandObject($command, $file->getPathname());
276 1
                    if ($command_obj instanceof Command) {
277 1
                        $commands[$command_name] = $command_obj;
278
                    }
279
                }
280
            } catch (Exception $e) {
281
                throw new TelegramException('Error getting commands from path: ' . $path, $e);
0 ignored issues
show
Bug introduced by
$e of type Exception is incompatible with the type integer expected by parameter $code of Longman\TelegramBot\Exce...xception::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

281
                throw new TelegramException('Error getting commands from path: ' . $path, /** @scrutinizer ignore-type */ $e);
Loading history...
282
            }
283
        }
284
285 1
        return $commands;
286
    }
287
288
    /**
289
     * Get an object instance of the passed command
290
     *
291
     * @param string $command
292
     * @param string $filepath
293
     *
294
     * @return Command|null
295
     */
296 1
    public function getCommandObject($command, $filepath = null)
297
    {
298 1
        $which = ['System'];
299 1
        $this->isAdmin() && $which[] = 'Admin';
300 1
        $which[] = 'User';
301
302 1
        foreach ($which as $auth) {
303 1
            if ($filepath) {
304 1
                $command_namespace = $this->getFileNamespace($filepath);
305
            } else {
306
                $command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands';
307
            }
308 1
            $command_class = $command_namespace . '\\' . $this->ucfirstUnicode($command) . 'Command';
309
310 1
            if (class_exists($command_class)) {
311 1
                $command_obj = new $command_class($this, $this->update);
312
313 1
                switch ($auth) {
314 1
                    case 'System':
315 1
                        if ($command_obj instanceof SystemCommand) {
316 1
                            return $command_obj;
317
                        }
318
                        break;
319
320
                    case 'Admin':
321
                        if ($command_obj instanceof AdminCommand) {
322
                            return $command_obj;
323
                        }
324
                        break;
325
326
                    case 'User':
327
                        if ($command_obj instanceof UserCommand) {
328
                            return $command_obj;
329
                        }
330
                        break;
331
                }
332
            }
333
        }
334
335
        return null;
336
    }
337
338
    /**
339
     * Get namespace from php file by src path
340
     *
341
     * @param string $src (absolute path to file)
342
     *
343
     * @return string ("Longman\TelegramBot\Commands\SystemCommands" for example)
344
     */
345 1
    protected function getFileNamespace($src)
346
    {
347 1
        $content = file_get_contents($src);
348 1
        if (preg_match('#^namespace\s+(.+?);$#sm', $content, $m)) {
349 1
            return $m[1];
350
        }
351
        return null;
352
    }
353
354
    /**
355
     * Set custom input string for debug purposes
356
     *
357
     * @param string $input (json format)
358
     *
359
     * @return Telegram
360
     */
361
    public function setCustomInput($input)
362
    {
363
        $this->input = $input;
364
365
        return $this;
366
    }
367
368
    /**
369
     * Get custom input string for debug purposes
370
     *
371
     * @return string
372
     */
373
    public function getCustomInput()
374
    {
375
        return $this->input;
376
    }
377
378
    /**
379
     * Get the ServerResponse of the last Command execution
380
     *
381
     * @return ServerResponse
382
     */
383
    public function getLastCommandResponse()
384
    {
385
        return $this->last_command_response;
386
    }
387
388
    /**
389
     * Handle getUpdates method
390
     *
391
     * @param int|null $limit
392
     * @param int|null $timeout
393
     *
394
     * @return ServerResponse
395
     * @throws TelegramException
396
     */
397
    public function handleGetUpdates($limit = null, $timeout = null)
398
    {
399
        if (empty($this->bot_username)) {
400
            throw new TelegramException('Bot Username is not defined!');
401
        }
402
403
        if (!DB::isDbConnected() && !$this->getupdates_without_database) {
404
            return new ServerResponse(
405
                [
406
                    'ok'          => false,
407
                    'description' => 'getUpdates needs MySQL connection! (This can be overridden - see documentation)',
408
                ],
409
                $this->bot_username
410
            );
411
        }
412
413
        $offset = 0;
414
415
        //Take custom input into account.
416
        if ($custom_input = $this->getCustomInput()) {
417
            $response = new ServerResponse(json_decode($custom_input, true), $this->bot_username);
418
        } else {
419
            if (DB::isDbConnected() && $last_update = DB::selectTelegramUpdate(1)) {
420
                //Get last update id from the database
421
                $last_update = reset($last_update);
422
423
                $this->last_update_id = isset($last_update['id']) ? $last_update['id'] : null;
424
            }
425
426
            if ($this->last_update_id !== null) {
427
                $offset = $this->last_update_id + 1;    //As explained in the telegram bot API documentation
428
            }
429
430
            $response = Request::getUpdates(
431
                [
432
                    'offset'  => $offset,
433
                    'limit'   => $limit,
434
                    'timeout' => $timeout,
435
                ]
436
            );
437
        }
438
439
        if ($response->isOk()) {
440
            $results = $response->getResult();
441
442
            //Process all updates
443
            /** @var Update $result */
444
            foreach ($results as $result) {
445
                $this->processUpdate($result);
446
            }
447
448
            if (!DB::isDbConnected() && !$custom_input && $this->last_update_id !== null && $offset === 0) {
449
                //Mark update(s) as read after handling
450
                Request::getUpdates(
451
                    [
452
                        'offset'  => $this->last_update_id + 1,
453
                        'limit'   => 1,
454
                        'timeout' => $timeout,
455
                    ]
456
                );
457
            }
458
        }
459
460
        return $response;
461
    }
462
463
    /**
464
     * Handle bot request from webhook
465
     *
466
     * @return bool
467
     *
468
     * @throws TelegramException
469
     */
470
    public function handle()
471
    {
472
        if (empty($this->bot_username)) {
473
            throw new TelegramException('Bot Username is not defined!');
474
        }
475
476
        $this->input = Request::getInput();
477
478
        if (empty($this->input)) {
479
            throw new TelegramException('Input is empty!');
480
        }
481
482
        $post = json_decode($this->input, true);
483
        if (empty($post)) {
484
            throw new TelegramException('Invalid JSON!');
485
        }
486
487
        if ($response = $this->processUpdate(new Update($post, $this->bot_username))) {
488
            return $response->isOk();
489
        }
490
491
        return false;
492
    }
493
494
    /**
495
     * Get the command name from the command type
496
     *
497
     * @param string $type
498
     *
499
     * @return string
500
     */
501
    protected function getCommandFromType($type)
502
    {
503
        return $this->ucfirstUnicode(str_replace('_', '', $type));
504
    }
505
506
    /**
507
     * Process bot Update request
508
     *
509
     * @param Update $update
510
     *
511
     * @return ServerResponse
512
     * @throws TelegramException
513
     */
514 1
    public function processUpdate(Update $update)
515
    {
516 1
        $this->update         = $update;
517 1
        $this->last_update_id = $update->getUpdateId();
518
519 1
        if (is_callable($this->update_filter)) {
520 1
            $reason = 'Update denied by update_filter';
521
            try {
522 1
                $allowed = (bool) call_user_func_array($this->update_filter, [$update, $this, &$reason]);
523
            } catch (\Exception $e) {
524
                $allowed = false;
525
            }
526
527 1
            if (!$allowed) {
528 1
                TelegramLog::debug($reason);
529 1
                return new ServerResponse(['ok' => false, 'description' => 'denied'], null);
530
            }
531
        }
532
533
        //Load admin commands
534
        if ($this->isAdmin()) {
535
            $this->addCommandsPath(TB_BASE_COMMANDS_PATH . '/AdminCommands', false);
536
        }
537
538
        //Make sure we have an up-to-date command list
539
        //This is necessary to "require" all the necessary command files!
540
        $this->commands_objects = $this->getCommandsList();
541
542
        //If all else fails, it's a generic message.
543
        $command = self::GENERIC_MESSAGE_COMMAND;
544
545
        $update_type = $this->update->getUpdateType();
546
        if ($update_type === 'message') {
547
            $message = $this->update->getMessage();
548
            $type    = $message->getType();
549
550
            // Let's check if the message object has the type field we're looking for...
551
            $command_tmp = $type === 'command' ? $message->getCommand() : $this->getCommandFromType($type);
552
            // ...and if a fitting command class is available.
553
            $command_obj = $this->getCommandObject($command_tmp);
554
555
            // Empty usage string denotes a non-executable command.
556
            // @see https://github.com/php-telegram-bot/core/issues/772#issuecomment-388616072
557
            if (
558
                ($command_obj === null && $type === 'command')
559
                || ($command_obj !== null && $command_obj->getUsage() !== '')
560
            ) {
561
                $command = $command_tmp;
562
            }
563
        } else {
564
            $command = $this->getCommandFromType($update_type);
565
        }
566
567
        //Make sure we don't try to process update that was already processed
568
        $last_id = DB::selectTelegramUpdate(1, $this->update->getUpdateId());
569
        if ($last_id && count($last_id) === 1) {
570
            TelegramLog::debug('Duplicate update received, processing aborted!');
571
            return Request::emptyResponse();
572
        }
573
574
        DB::insertRequest($this->update);
575
576
        return $this->executeCommand($command);
577
    }
578
579
    /**
580
     * Execute /command
581
     *
582
     * @param string $command
583
     *
584
     * @return ServerResponse
585
     * @throws TelegramException
586
     */
587
    public function executeCommand($command)
588
    {
589
        $command = mb_strtolower($command);
590
591
        if (isset($this->commands_objects[$command])) {
592
            $command_obj = $this->commands_objects[$command];
593
        } else {
594
            $command_obj = $this->getCommandObject($command);
595
        }
596
597
        if (!$command_obj || !$command_obj->isEnabled()) {
598
            //Failsafe in case the Generic command can't be found
599
            if ($command === self::GENERIC_COMMAND) {
600
                throw new TelegramException('Generic command missing!');
601
            }
602
603
            //Handle a generic command or non existing one
604
            $this->last_command_response = $this->executeCommand(self::GENERIC_COMMAND);
605
        } else {
606
            //execute() method is executed after preExecute()
607
            //This is to prevent executing a DB query without a valid connection
608
            $this->last_command_response = $command_obj->preExecute();
609
        }
610
611
        return $this->last_command_response;
612
    }
613
614
    /**
615
     * Sanitize Command
616
     *
617
     * @param string $command
618
     *
619
     * @return string
620
     */
621 1
    protected function sanitizeCommand($command)
622
    {
623 1
        return str_replace(' ', '', $this->ucwordsUnicode(str_replace('_', ' ', $command)));
624
    }
625
626
    /**
627
     * Enable a single Admin account
628
     *
629
     * @param integer $admin_id Single admin id
630
     *
631
     * @return Telegram
632
     */
633 1
    public function enableAdmin($admin_id)
634
    {
635 1
        if (!is_int($admin_id) || $admin_id <= 0) {
0 ignored issues
show
introduced by
The condition is_int($admin_id) is always true.
Loading history...
636 1
            TelegramLog::error('Invalid value "' . $admin_id . '" for admin.');
637 1
        } elseif (!in_array($admin_id, $this->admins_list, true)) {
638 1
            $this->admins_list[] = $admin_id;
639
        }
640
641 1
        return $this;
642
    }
643
644
    /**
645
     * Enable a list of Admin Accounts
646
     *
647
     * @param array $admin_ids List of admin ids
648
     *
649
     * @return Telegram
650
     */
651 1
    public function enableAdmins(array $admin_ids)
652
    {
653 1
        foreach ($admin_ids as $admin_id) {
654 1
            $this->enableAdmin($admin_id);
655
        }
656
657 1
        return $this;
658
    }
659
660
    /**
661
     * Get list of admins
662
     *
663
     * @return array
664
     */
665 1
    public function getAdminList()
666
    {
667 1
        return $this->admins_list;
668
    }
669
670
    /**
671
     * Check if the passed user is an admin
672
     *
673
     * If no user id is passed, the current update is checked for a valid message sender.
674
     *
675
     * @param int|null $user_id
676
     *
677
     * @return bool
678
     */
679 1
    public function isAdmin($user_id = null)
680
    {
681 1
        if ($user_id === null && $this->update !== null) {
682
            //Try to figure out if the user is an admin
683
            $update_methods = [
684
                'getMessage',
685
                'getEditedMessage',
686
                'getChannelPost',
687
                'getEditedChannelPost',
688
                'getInlineQuery',
689
                'getChosenInlineResult',
690
                'getCallbackQuery',
691
            ];
692
            foreach ($update_methods as $update_method) {
693
                $object = call_user_func([$this->update, $update_method]);
694
                if ($object !== null && $from = $object->getFrom()) {
695
                    $user_id = $from->getId();
696
                    break;
697
                }
698
            }
699
        }
700
701 1
        return ($user_id === null) ? false : in_array($user_id, $this->admins_list, true);
702
    }
703
704
    /**
705
     * Check if user required the db connection
706
     *
707
     * @return bool
708
     */
709
    public function isDbEnabled()
710
    {
711
        if ($this->mysql_enabled) {
712
            return true;
713
        } else {
714
            return false;
715
        }
716
    }
717
718
    /**
719
     * Add a single custom commands path
720
     *
721
     * @param string $path   Custom commands path to add
722
     * @param bool   $before If the path should be prepended or appended to the list
723
     *
724
     * @return Telegram
725
     */
726 30
    public function addCommandsPath($path, $before = true)
727
    {
728 30
        if (!is_dir($path)) {
729 1
            TelegramLog::error('Commands path "' . $path . '" does not exist.');
730 30
        } elseif (!in_array($path, $this->commands_paths, true)) {
731 30
            if ($before) {
732 30
                array_unshift($this->commands_paths, $path);
733
            } else {
734
                $this->commands_paths[] = $path;
735
            }
736
        }
737
738 30
        return $this;
739
    }
740
741
    /**
742
     * Add multiple custom commands paths
743
     *
744
     * @param array $paths  Custom commands paths to add
745
     * @param bool  $before If the paths should be prepended or appended to the list
746
     *
747
     * @return Telegram
748
     */
749 1
    public function addCommandsPaths(array $paths, $before = true)
750
    {
751 1
        foreach ($paths as $path) {
752 1
            $this->addCommandsPath($path, $before);
753
        }
754
755 1
        return $this;
756
    }
757
758
    /**
759
     * Return the list of commands paths
760
     *
761
     * @return array
762
     */
763 1
    public function getCommandsPaths()
764
    {
765 1
        return $this->commands_paths;
766
    }
767
768
    /**
769
     * Set custom upload path
770
     *
771
     * @param string $path Custom upload path
772
     *
773
     * @return Telegram
774
     */
775
    public function setUploadPath($path)
776
    {
777
        $this->upload_path = $path;
778
779
        return $this;
780
    }
781
782
    /**
783
     * Get custom upload path
784
     *
785
     * @return string
786
     */
787
    public function getUploadPath()
788
    {
789
        return $this->upload_path;
790
    }
791
792
    /**
793
     * Set custom download path
794
     *
795
     * @param string $path Custom download path
796
     *
797
     * @return Telegram
798
     */
799
    public function setDownloadPath($path)
800
    {
801
        $this->download_path = $path;
802
803
        return $this;
804
    }
805
806
    /**
807
     * Get custom download path
808
     *
809
     * @return string
810
     */
811
    public function getDownloadPath()
812
    {
813
        return $this->download_path;
814
    }
815
816
    /**
817
     * Set command config
818
     *
819
     * Provide further variables to a particular commands.
820
     * For example you can add the channel name at the command /sendtochannel
821
     * Or you can add the api key for external service.
822
     *
823
     * @param string $command
824
     * @param array  $config
825
     *
826
     * @return Telegram
827
     */
828 13
    public function setCommandConfig($command, array $config)
829
    {
830 13
        $this->commands_config[$command] = $config;
831
832 13
        return $this;
833
    }
834
835
    /**
836
     * Get command config
837
     *
838
     * @param string $command
839
     *
840
     * @return array
841
     */
842 14
    public function getCommandConfig($command)
843
    {
844 14
        return isset($this->commands_config[$command]) ? $this->commands_config[$command] : [];
845
    }
846
847
    /**
848
     * Get API key
849
     *
850
     * @return string
851
     */
852 1
    public function getApiKey()
853
    {
854 1
        return $this->api_key;
855
    }
856
857
    /**
858
     * Get Bot name
859
     *
860
     * @return string
861
     */
862 2
    public function getBotUsername()
863
    {
864 2
        return $this->bot_username;
865
    }
866
867
    /**
868
     * Get Bot Id
869
     *
870
     * @return string
871
     */
872
    public function getBotId()
873
    {
874
        return $this->bot_id;
875
    }
876
877
    /**
878
     * Get Version
879
     *
880
     * @return string
881
     */
882
    public function getVersion()
883
    {
884
        return $this->version;
885
    }
886
887
    /**
888
     * Set Webhook for bot
889
     *
890
     * @param string $url
891
     * @param array  $data Optional parameters.
892
     *
893
     * @return ServerResponse
894
     * @throws TelegramException
895
     */
896
    public function setWebhook($url, array $data = [])
897
    {
898
        if (empty($url)) {
899
            throw new TelegramException('Hook url is empty!');
900
        }
901
902
        $data        = array_intersect_key($data, array_flip([
903
            'certificate',
904
            'max_connections',
905
            'allowed_updates',
906
        ]));
907
        $data['url'] = $url;
908
909
        // If the certificate is passed as a path, encode and add the file to the data array.
910
        if (!empty($data['certificate']) && is_string($data['certificate'])) {
911
            $data['certificate'] = Request::encodeFile($data['certificate']);
912
        }
913
914
        $result = Request::setWebhook($data);
915
916
        if (!$result->isOk()) {
917
            throw new TelegramException(
918
                'Webhook was not set! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
919
            );
920
        }
921
922
        return $result;
923
    }
924
925
    /**
926
     * Delete any assigned webhook
927
     *
928
     * @return mixed
929
     * @throws TelegramException
930
     */
931
    public function deleteWebhook()
932
    {
933
        $result = Request::deleteWebhook();
934
935
        if (!$result->isOk()) {
936
            throw new TelegramException(
937
                'Webhook was not deleted! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
938
            );
939
        }
940
941
        return $result;
942
    }
943
944
    /**
945
     * Replace function `ucwords` for UTF-8 characters in the class definition and commands
946
     *
947
     * @param string $str
948
     * @param string $encoding (default = 'UTF-8')
949
     *
950
     * @return string
951
     */
952 1
    protected function ucwordsUnicode($str, $encoding = 'UTF-8')
953
    {
954 1
        return mb_convert_case($str, MB_CASE_TITLE, $encoding);
955
    }
956
957
    /**
958
     * Replace function `ucfirst` for UTF-8 characters in the class definition and commands
959
     *
960
     * @param string $str
961
     * @param string $encoding (default = 'UTF-8')
962
     *
963
     * @return string
964
     */
965 1
    protected function ucfirstUnicode($str, $encoding = 'UTF-8')
966
    {
967 1
        return mb_strtoupper(mb_substr($str, 0, 1, $encoding), $encoding)
968 1
            . mb_strtolower(mb_substr($str, 1, mb_strlen($str), $encoding), $encoding);
969
    }
970
971
    /**
972
     * Enable requests limiter
973
     *
974
     * @param array $options
975
     *
976
     * @return Telegram
977
     * @throws TelegramException
978
     */
979
    public function enableLimiter(array $options = [])
980
    {
981
        Request::setLimiter(true, $options);
982
983
        return $this;
984
    }
985
986
    /**
987
     * Run provided commands
988
     *
989
     * @param array $commands
990
     *
991
     * @throws TelegramException
992
     */
993
    public function runCommands($commands)
994
    {
995
        if (!is_array($commands) || empty($commands)) {
0 ignored issues
show
introduced by
The condition is_array($commands) is always true.
Loading history...
996
            throw new TelegramException('No command(s) provided!');
997
        }
998
999
        $this->run_commands = true;
1000
1001
        $result = Request::getMe();
1002
1003
        if ($result->isOk()) {
1004
            $result = $result->getResult();
1005
1006
            $bot_id       = $result->getId();
1007
            $bot_name     = $result->getFirstName();
1008
            $bot_username = $result->getUsername();
1009
        } else {
1010
            $bot_id       = $this->getBotId();
1011
            $bot_name     = $this->getBotUsername();
1012
            $bot_username = $this->getBotUsername();
1013
        }
1014
1015
1016
        $this->enableAdmin($bot_id);    // Give bot access to admin commands
1017
        $this->getCommandsList();       // Load full commands list
1018
1019
        foreach ($commands as $command) {
1020
            $this->update = new Update(
1021
                [
1022
                    'update_id' => 0,
1023
                    'message'   => [
1024
                        'message_id' => 0,
1025
                        'from'       => [
1026
                            'id'         => $bot_id,
1027
                            'first_name' => $bot_name,
1028
                            'username'   => $bot_username,
1029
                        ],
1030
                        'date'       => time(),
1031
                        'chat'       => [
1032
                            'id'   => $bot_id,
1033
                            'type' => 'private',
1034
                        ],
1035
                        'text'       => $command,
1036
                    ],
1037
                ]
1038
            );
1039
1040
            $this->executeCommand($this->update->getMessage()->getCommand());
1041
        }
1042
    }
1043
1044
    /**
1045
     * Is this session initiated by runCommands()
1046
     *
1047
     * @return bool
1048
     */
1049
    public function isRunCommands()
1050
    {
1051
        return $this->run_commands;
1052
    }
1053
1054
    /**
1055
     * Switch to enable running getUpdates without a database
1056
     *
1057
     * @param bool $enable
1058
     */
1059
    public function useGetUpdatesWithoutDatabase($enable = true)
1060
    {
1061
        $this->getupdates_without_database = $enable;
1062
    }
1063
1064
    /**
1065
     * Return last update id
1066
     *
1067
     * @return int
1068
     */
1069
    public function getLastUpdateId()
1070
    {
1071
        return $this->last_update_id;
1072
    }
1073
1074
    /**
1075
     * Set an update filter callback
1076
     *
1077
     * @param callable $callback
1078
     *
1079
     * @return Telegram
1080
     */
1081 1
    public function setUpdateFilter(callable $callback)
1082
    {
1083 1
        $this->update_filter = $callback;
1084
1085 1
        return $this;
1086
    }
1087
1088
    /**
1089
     * Return update filter callback
1090
     *
1091
     * @return callable|null
1092
     */
1093
    public function getUpdateFilter()
1094
    {
1095
        return $this->update_filter;
1096
    }
1097
}
1098