Completed
Push — feature/refactor-app-design ( d959a3 )
by Avtandil
03:51
created

Telegram::enableAdmin()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 6
cts 6
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 6
nc 3
nop 1
crap 4
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 13 and the first side effect is on line 13.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

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

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
837
    }
838
839
    /**
840
     * Set Webhook for bot
841
     *
842
     * @param string $url
843
     * @param array $data Optional parameters.
844
     *
845
     * @return \Longman\TelegramBot\Http\ServerResponse
846
     * @throws \Longman\TelegramBot\Exception\TelegramException
847
     */
848
    public function setWebhook($url, array $data = [])
849
    {
850
        if (empty($url)) {
851
            throw new TelegramException('Hook url is empty!');
852
        }
853
854
        $data = array_intersect_key($data, array_flip([
855
            'certificate',
856
            'max_connections',
857
            'allowed_updates',
858
        ]));
859
        $data['url'] = $url;
860
861
        // If the certificate is passed as a path, encode and add the file to the data array.
862
        if (! empty($data['certificate']) && is_string($data['certificate'])) {
863
            $data['certificate'] = Client::encodeFile($data['certificate']);
864
        }
865
866
        $result = Client::setWebhook($data);
867
868 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...
869
            throw new TelegramException(
870
                'Webhook was not set! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
871
            );
872
        }
873
874
        return $result;
875
    }
876
877
    /**
878
     * Delete any assigned webhook
879
     *
880
     * @return mixed
881
     * @throws \Longman\TelegramBot\Exception\TelegramException
882
     */
883
    public function deleteWebhook()
884
    {
885
        $result = Client::deleteWebhook();
886
887 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...
888
            throw new TelegramException(
889
                'Webhook was not deleted! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
890
            );
891
        }
892
893
        return $result;
894
    }
895
896
    /**
897
     * Replace function `ucwords` for UTF-8 characters in the class definition and commands
898
     *
899
     * @param string $str
900
     * @param string $encoding (default = 'UTF-8')
901
     *
902
     * @return string
903
     */
904 2
    protected function ucwordsUnicode($str, $encoding = 'UTF-8')
905
    {
906 2
        return mb_convert_case($str, MB_CASE_TITLE, $encoding);
907
    }
908
909
    /**
910
     * Replace function `ucfirst` for UTF-8 characters in the class definition and commands
911
     *
912
     * @param string $str
913
     * @param string $encoding (default = 'UTF-8')
914
     *
915
     * @return string
916
     */
917 2
    protected function ucfirstUnicode($str, $encoding = 'UTF-8')
918
    {
919 2
        return mb_strtoupper(mb_substr($str, 0, 1, $encoding), $encoding)
920 2
            . mb_strtolower(mb_substr($str, 1, mb_strlen($str), $encoding), $encoding);
921
    }
922
923
    /**
924
     * Enable Botan.io integration
925
     *
926
     * @param  string $token
927
     * @param  array $options
928
     *
929
     * @return \Longman\TelegramBot\Telegram
930
     * @throws \Longman\TelegramBot\Exception\TelegramException
931
     */
932
    public function enableBotan($token, array $options = [])
933
    {
934
        Botan::initializeBotan($token, $options);
935
        $this->botan_enabled = true;
936
937
        return $this;
938
    }
939
940
    /**
941
     * Enable requests limiter
942
     *
943
     * @param  array $options
944
     *
945
     * @return \Longman\TelegramBot\Telegram
946
     */
947
    public function enableLimiter(array $options = [])
948
    {
949
        Client::setLimiter(true, $options);
950
951
        return $this;
952
    }
953
954
    /**
955
     * Run provided commands
956
     *
957
     * @param array $commands
958
     *
959
     * @throws TelegramException
960
     */
961
    public function runCommands($commands)
962
    {
963
        if (! is_array($commands) || empty($commands)) {
964
            throw new TelegramException('No command(s) provided!');
965
        }
966
967
        $this->run_commands = true;
968
        $this->botan_enabled = false;   // Force disable Botan.io integration, we don't want to track self-executed commands!
969
970
        $result = Client::getMe();
971
972
        if ($result->isOk()) {
973
            $result = $result->getResult();
974
975
            $bot_id = $result->getId();
976
            $bot_name = $result->getFirstName();
977
            $bot_username = $result->getUsername();
978
        } else {
979
            $bot_id = $this->getBotId();
980
            $bot_name = $this->getBotUsername();
981
            $bot_username = $this->getBotUsername();
982
        }
983
984
        $this->enableAdmin($bot_id);    // Give bot access to admin commands
985
        $this->getCommandsList();       // Load full commands list
986
987
        foreach ($commands as $command) {
988
            $this->update = new Update(
989
                [
990
                    'update_id' => 0,
991
                    'message'   => [
992
                        'message_id' => 0,
993
                        'from'       => [
994
                            'id'         => $bot_id,
995
                            'first_name' => $bot_name,
996
                            'username'   => $bot_username,
997
                        ],
998
                        'date'       => time(),
999
                        'chat'       => [
1000
                            'id'   => $bot_id,
1001
                            'type' => 'private',
1002
                        ],
1003
                        'text'       => $command,
1004
                    ],
1005
                ]
1006
            );
1007
1008
            $this->executeCommand($this->update->getMessage()->getCommand());
1009
        }
1010
    }
1011
1012
    /**
1013
     * Is this session initiated by runCommands()
1014
     *
1015
     * @return bool
1016
     */
1017
    public function isRunCommands()
1018
    {
1019
        return $this->run_commands;
1020
    }
1021
1022
    /**
1023
     * Switch to enable running getUpdates without a database
1024
     *
1025
     * @param bool $enable
1026
     */
1027
    public function useGetUpdatesWithoutDatabase($enable = true)
1028
    {
1029
        $this->getupdates_without_database = $enable;
1030
    }
1031
1032
    /**
1033
     * Return last update id
1034
     *
1035
     * @return int
1036
     */
1037
    public function getLastUpdateId()
1038
    {
1039
        return $this->last_update_id;
1040
    }
1041
}
1042