Completed
Push — master ( ef9e39...904d42 )
by
unknown
08:21 queued 06:18
created

DB   D

Complexity

Total Complexity 98

Size/Duplication

Total Lines 999
Duplicated Lines 14.91 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 33.33%

Importance

Changes 0
Metric Value
wmc 98
lcom 1
cbo 9
dl 149
loc 999
ccs 149
cts 447
cp 0.3333
rs 4.4444
c 0
b 0
f 0

18 Methods

Rating   Name   Duplication   Size   Complexity  
B initialize() 0 28 3
A externalInitialize() 0 18 2
A defineTables() 0 20 3
A isDbConnected() 0 4 1
B selectTelegramUpdate() 26 26 4
B selectMessages() 27 27 4
A getTimestamp() 0 8 2
A entitiesArrayToJson() 0 13 2
C insertTelegramUpdate() 0 38 8
B insertUser() 0 57 5
B insertChat() 0 41 4
C insertRequest() 18 67 11
B insertInlineQueryRequest() 39 39 4
B insertChosenInlineResultRequest() 39 39 4
B insertCallbackQueryRequest() 0 61 6
F insertMessageRequest() 0 156 11
B insertEditedMessageRequest() 0 55 5
F selectChats() 0 92 19

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 DB 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 DB, 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
 * Written by Marco Boretto <[email protected]>
10
 */
11
12
namespace Longman\TelegramBot;
13
14
use Longman\TelegramBot\Entities\CallbackQuery;
15
use Longman\TelegramBot\Entities\Chat;
16
use Longman\TelegramBot\Entities\ChosenInlineResult;
17
use Longman\TelegramBot\Entities\InlineQuery;
18
use Longman\TelegramBot\Entities\Message;
19
use Longman\TelegramBot\Entities\ReplyToMessage;
20
use Longman\TelegramBot\Entities\Update;
21
use Longman\TelegramBot\Entities\User;
22
use Longman\TelegramBot\Exception\TelegramException;
23
use PDO;
24
use PDOException;
25
26
class DB
27
{
28
    /**
29
     * MySQL credentials
30
     *
31
     * @var array
32
     */
33
    static protected $mysql_credentials = [];
34
35
    /**
36
     * PDO object
37
     *
38
     * @var PDO
39
     */
40
    static protected $pdo;
41
42
    /**
43
     * Table prefix
44
     *
45
     * @var string
46
     */
47
    static protected $table_prefix;
48
49
    /**
50
     * Telegram class object
51
     *
52
     * @var \Longman\TelegramBot\Telegram
53
     */
54
    static protected $telegram;
55
56
    /**
57
     * Initialize
58
     *
59
     * @param array                         $credentials  Database connection details
60
     * @param \Longman\TelegramBot\Telegram $telegram     Telegram object to connect with this object
61
     * @param string                        $table_prefix Table prefix
62
     * @param string                        $encoding     Database character encoding
63
     *
64
     * @return PDO PDO database object
65
     * @throws \Longman\TelegramBot\Exception\TelegramException
66
     */
67 9
    public static function initialize(
68
        array $credentials,
69
        Telegram $telegram,
70
        $table_prefix = null,
71
        $encoding = 'utf8mb4'
72
    ) {
73 9
        if (empty($credentials)) {
74
            throw new TelegramException('MySQL credentials not provided!');
75
        }
76
77 9
        $dsn     = 'mysql:host=' . $credentials['host'] . ';dbname=' . $credentials['database'];
78 9
        $options = [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . $encoding];
79
        try {
80 9
            $pdo = new PDO($dsn, $credentials['user'], $credentials['password'], $options);
81 9
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
82
        } catch (PDOException $e) {
83
            throw new TelegramException($e->getMessage());
84
        }
85
86 9
        self::$pdo               = $pdo;
87 9
        self::$telegram          = $telegram;
88 9
        self::$mysql_credentials = $credentials;
89 9
        self::$table_prefix      = $table_prefix;
90
91 9
        self::defineTables();
92
93 9
        return self::$pdo;
94
    }
95
96
    /**
97
     * External Initialize
98
     *
99
     * Let you use the class with an external already existing Pdo Mysql connection.
100
     *
101
     * @param PDO                           $external_pdo_connection PDO database object
102
     * @param \Longman\TelegramBot\Telegram $telegram                Telegram object to connect with this object
103
     * @param string                        $table_prefix            Table prefix
104
     *
105
     * @return PDO PDO database object
106
     * @throws \Longman\TelegramBot\Exception\TelegramException
107
     */
108
    public static function externalInitialize(
109
        $external_pdo_connection,
110
        Telegram $telegram,
111
        $table_prefix = null
112
    ) {
113
        if ($external_pdo_connection === null) {
114
            throw new TelegramException('MySQL external connection not provided!');
115
        }
116
117
        self::$pdo               = $external_pdo_connection;
118
        self::$telegram          = $telegram;
119
        self::$mysql_credentials = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $mysql_credentials.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
120
        self::$table_prefix      = $table_prefix;
121
122
        self::defineTables();
123
124
        return self::$pdo;
125
    }
126
127
    /**
128
     * Define all the tables with the proper prefix
129
     */
130 9
    protected static function defineTables()
131
    {
132
        $tables = [
133 9
            'callback_query',
134
            'chat',
135
            'chosen_inline_result',
136
            'edited_message',
137
            'inline_query',
138
            'message',
139
            'telegram_update',
140
            'user',
141
            'user_chat',
142
        ];
143 9
        foreach ($tables as $table) {
144 9
            $table_name = 'TB_' . strtoupper($table);
145 9
            if (!defined($table_name)) {
146 9
                define($table_name, self::$table_prefix . $table);
147
            }
148
        }
149 9
    }
150
151
    /**
152
     * Check if database connection has been created
153
     *
154
     * @return bool
155
     */
156 9
    public static function isDbConnected()
157
    {
158 9
        return self::$pdo !== null;
159
    }
160
161
    /**
162
     * Fetch update(s) from DB
163
     *
164
     * @param int $limit Limit the number of updates to fetch
165
     *
166
     * @return array|bool Fetched data or false if not connected
167
     * @throws \Longman\TelegramBot\Exception\TelegramException
168
     */
169 View Code Duplication
    public static function selectTelegramUpdate($limit = 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...
170
    {
171
        if (!self::isDbConnected()) {
172
            return false;
173
        }
174
175
        try {
176
            $sql = '
177
                SELECT `id`
178
                FROM `' . TB_TELEGRAM_UPDATE . '`
179
                ORDER BY `id` DESC
180
            ';
181
182
            if ($limit !== null) {
183
                $sql .= 'LIMIT :limit';
184
            }
185
186
            $sth = self::$pdo->prepare($sql);
187
            $sth->bindParam(':limit', $limit, PDO::PARAM_INT);
188
            $sth->execute();
189
190
            return $sth->fetchAll(PDO::FETCH_ASSOC);
191
        } catch (PDOException $e) {
192
            throw new TelegramException($e->getMessage());
193
        }
194
    }
195
196
    /**
197
     * Fetch message(s) from DB
198
     *
199
     * @param int $limit Limit the number of messages to fetch
200
     *
201
     * @return array|bool Fetched data or false if not connected
202
     * @throws \Longman\TelegramBot\Exception\TelegramException
203
     */
204 View Code Duplication
    public static function selectMessages($limit = 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...
205
    {
206
        if (!self::isDbConnected()) {
207
            return false;
208
        }
209
210
        try {
211
            $sql = '
212
                SELECT *
213
                FROM `' . TB_MESSAGE . '`
214
                WHERE `update_id` != 0
215
                ORDER BY `message_id` DESC
216
            ';
217
218
            if ($limit !== null) {
219
                $sql .= 'LIMIT :limit';
220
            }
221
222
            $sth = self::$pdo->prepare($sql);
223
            $sth->bindParam(':limit', $limit, PDO::PARAM_INT);
224
            $sth->execute();
225
226
            return $sth->fetchAll(PDO::FETCH_ASSOC);
227
        } catch (PDOException $e) {
228
            throw new TelegramException($e->getMessage());
229
        }
230
    }
231
232
    /**
233
     * Convert from unix timestamp to timestamp
234
     *
235
     * @param int $time Unix timestamp (if null, current timestamp is used)
236
     *
237
     * @return string
238
     */
239 7
    protected static function getTimestamp($time = null)
240
    {
241 7
        if ($time === null) {
242 6
            $time = time();
243
        }
244
245 7
        return date('Y-m-d H:i:s', $time);
246
    }
247
248
    /**
249
     * Convert array of Entity items to a JSON array
250
     *
251
     * @todo Find a better way, as json_* functions are very heavy
252
     *
253
     * @param array|null $entities
254
     * @param mixed      $default
255
     *
256
     * @return mixed
257
     */
258 6
    public static function entitiesArrayToJson($entities, $default = null)
259
    {
260 6
        if (!is_array($entities)) {
261 6
            return $default;
262
        }
263
264
        //Convert each Entity item into an object based on its JSON reflection
265
        $json_entities = array_map(function ($entity) {
266
            return json_decode($entity, true);
267
        }, $entities);
268
269
        return json_encode($json_entities);
270
    }
271
272
    /**
273
     * Insert entry to telegram_update table
274
     *
275
     * @param int $id
276
     * @param int $chat_id
277
     * @param int $message_id
278
     * @param int $inline_query_id
279
     * @param int $chosen_inline_result_id
280
     * @param int $callback_query_id
281
     * @param int $edited_message_id
282
     *
283
     * @return bool If the insert was successful
284
     * @throws \Longman\TelegramBot\Exception\TelegramException
285
     */
286
    public static function insertTelegramUpdate(
287
        $id,
288
        $chat_id,
289
        $message_id,
290
        $inline_query_id,
291
        $chosen_inline_result_id,
292
        $callback_query_id,
293
        $edited_message_id
294
    ) {
295
        if ($message_id === null && $inline_query_id === null && $chosen_inline_result_id === null && $callback_query_id === null && $edited_message_id === null) {
296
            throw new TelegramException('message_id, inline_query_id, chosen_inline_result_id, callback_query_id, edited_message_id are all null');
297
        }
298
299
        if (!self::isDbConnected()) {
300
            return false;
301
        }
302
303
        try {
304
            $sth = self::$pdo->prepare('
305
                INSERT IGNORE INTO `' . TB_TELEGRAM_UPDATE . '`
306
                (`id`, `chat_id`, `message_id`, `inline_query_id`, `chosen_inline_result_id`, `callback_query_id`, `edited_message_id`)
307
                VALUES
308
                (:id, :chat_id, :message_id, :inline_query_id, :chosen_inline_result_id, :callback_query_id, :edited_message_id)
309
            ');
310
311
            $sth->bindParam(':id', $id, PDO::PARAM_INT);
312
            $sth->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
313
            $sth->bindParam(':message_id', $message_id, PDO::PARAM_INT);
314
            $sth->bindParam(':inline_query_id', $inline_query_id, PDO::PARAM_INT);
315
            $sth->bindParam(':chosen_inline_result_id', $chosen_inline_result_id, PDO::PARAM_INT);
316
            $sth->bindParam(':callback_query_id', $callback_query_id, PDO::PARAM_INT);
317
            $sth->bindParam(':edited_message_id', $edited_message_id, PDO::PARAM_INT);
318
319
            return $sth->execute();
320
        } catch (PDOException $e) {
321
            throw new TelegramException($e->getMessage());
322
        }
323
    }
324
325
    /**
326
     * Insert users and save their connection to chats
327
     *
328
     * @param  \Longman\TelegramBot\Entities\User $user
329
     * @param  string                             $date
330
     * @param  \Longman\TelegramBot\Entities\Chat $chat
331
     *
332
     * @return bool If the insert was successful
333
     * @throws \Longman\TelegramBot\Exception\TelegramException
334
     */
335 6
    public static function insertUser(User $user, $date, Chat $chat = null)
336
    {
337 6
        if (!self::isDbConnected()) {
338
            return false;
339
        }
340
341 6
        $user_id    = $user->getId();
342 6
        $username   = $user->getUsername();
343 6
        $first_name = $user->getFirstName();
344 6
        $last_name  = $user->getLastName();
345
346
        try {
347 6
            $sth = self::$pdo->prepare('
348 6
                INSERT INTO `' . TB_USER . '`
349
                (`id`, `username`, `first_name`, `last_name`, `created_at`, `updated_at`)
350
                VALUES
351
                (:id, :username, :first_name, :last_name, :date, :date)
352
                ON DUPLICATE KEY UPDATE
353
                    `username`   = :username,
354
                    `first_name` = :first_name,
355
                    `last_name`  = :last_name,
356
                    `updated_at` = :date
357 6
            ');
358
359 6
            $sth->bindParam(':id', $user_id, PDO::PARAM_INT);
360 6
            $sth->bindParam(':username', $username, PDO::PARAM_STR, 255);
361 6
            $sth->bindParam(':first_name', $first_name, PDO::PARAM_STR, 255);
362 6
            $sth->bindParam(':last_name', $last_name, PDO::PARAM_STR, 255);
363 6
            $sth->bindParam(':date', $date, PDO::PARAM_STR);
364
365 6
            $status = $sth->execute();
366
        } catch (PDOException $e) {
367
            throw new TelegramException($e->getMessage());
368
        }
369
370
        //insert also the relationship to the chat into user_chat table
371 6
        if ($chat instanceof Chat) {
372 6
            $chat_id = $chat->getId();
373
            try {
374 6
                $sth = self::$pdo->prepare('
375 6
                    INSERT IGNORE INTO `' . TB_USER_CHAT . '`
376
                    (`user_id`, `chat_id`)
377
                    VALUES
378
                    (:user_id, :chat_id)
379 6
                ');
380
381 6
                $sth->bindParam(':user_id', $user_id, PDO::PARAM_INT);
382 6
                $sth->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
383
384 6
                $status = $sth->execute();
385
            } catch (PDOException $e) {
386
                throw new TelegramException($e->getMessage());
387
            }
388
        }
389
390 6
        return $status;
391
    }
392
393
    /**
394
     * Insert chat
395
     *
396
     * @param  \Longman\TelegramBot\Entities\Chat $chat
397
     * @param  string                             $date
398
     * @param  int                                $migrate_to_chat_id
399
     *
400
     * @return bool If the insert was successful
401
     * @throws \Longman\TelegramBot\Exception\TelegramException
402
     */
403 6
    public static function insertChat(Chat $chat, $date, $migrate_to_chat_id = null)
404
    {
405 6
        if (!self::isDbConnected()) {
406
            return false;
407
        }
408
409 6
        $chat_id    = $chat->getId();
410 6
        $chat_title = $chat->getTitle();
411 6
        $chat_type  = $chat->getType();
412
413
        try {
414 6
            $sth = self::$pdo->prepare('
415 6
                INSERT INTO `' . TB_CHAT . '`
416
                (`id`, `type`, `title`, `created_at` ,`updated_at`, `old_id`)
417
                VALUES
418
                (:id, :type, :title, :date, :date, :oldid)
419
                ON DUPLICATE KEY UPDATE
420
                    `type`       = :type,
421
                    `title`      = :title,
422
                    `updated_at` = :date
423 6
            ');
424
425 6
            if ($migrate_to_chat_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $migrate_to_chat_id of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
426
                $chat_type = 'supergroup';
427
428
                $sth->bindParam(':id', $migrate_to_chat_id, PDO::PARAM_INT);
429
                $sth->bindParam(':oldid', $chat_id, PDO::PARAM_INT);
430
            } else {
431 6
                $sth->bindParam(':id', $chat_id, PDO::PARAM_INT);
432 6
                $sth->bindParam(':oldid', $migrate_to_chat_id, PDO::PARAM_INT);
433
            }
434
435 6
            $sth->bindParam(':type', $chat_type, PDO::PARAM_INT);
436 6
            $sth->bindParam(':title', $chat_title, PDO::PARAM_STR, 255);
437 6
            $sth->bindParam(':date', $date, PDO::PARAM_STR);
438
439 6
            return $sth->execute();
440
        } catch (PDOException $e) {
441
            throw new TelegramException($e->getMessage());
442
        }
443
    }
444
445
    /**
446
     * Insert request into database
447
     *
448
     * @todo self::$pdo->lastInsertId() - unsafe usage if expected previous insert fails?
449
     *
450
     * @param \Longman\TelegramBot\Entities\Update $update
451
     *
452
     * @return bool
453
     * @throws \Longman\TelegramBot\Exception\TelegramException
454
     */
455
    public static function insertRequest(Update $update)
456
    {
457
        $update_id   = $update->getUpdateId();
458
        $update_type = $update->getUpdateType();
459
460
        if ($update_type === 'message') {
461
            $message = $update->getMessage();
462
463
            if (self::insertMessageRequest($message)) {
464
                $message_id = $message->getMessageId();
465
                $chat_id    = $message->getChat()->getId();
466
467
                return self::insertTelegramUpdate($update_id, $chat_id, $message_id, null, null, null, null);
468
            }
469 View Code Duplication
        } elseif ($update_type === 'inline_query') {
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...
470
            $inline_query = $update->getInlineQuery();
471
472
            if (self::insertInlineQueryRequest($inline_query)) {
473
                $inline_query_id = $inline_query->getId();
474
475
                return self::insertTelegramUpdate($update_id, null, null, $inline_query_id, null, null, null);
476
            }
477
        } elseif ($update_type === 'chosen_inline_result') {
478
            $chosen_inline_result = $update->getChosenInlineResult();
479
480
            if (self::insertChosenInlineResultRequest($chosen_inline_result)) {
481
                $chosen_inline_result_local_id = self::$pdo->lastInsertId();
482
483
                return self::insertTelegramUpdate(
484
                    $update_id,
485
                    null,
486
                    null,
487
                    null,
488
                    $chosen_inline_result_local_id,
489
                    null,
490
                    null
491
                );
492
            }
493 View Code Duplication
        } elseif ($update_type === 'callback_query') {
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...
494
            $callback_query = $update->getCallbackQuery();
495
496
            if (self::insertCallbackQueryRequest($callback_query)) {
497
                $callback_query_id = $callback_query->getId();
498
499
                return self::insertTelegramUpdate($update_id, null, null, null, null, $callback_query_id, null);
500
            }
501
        } elseif ($update_type === 'edited_message') {
502
            $edited_message = $update->getEditedMessage();
503
504
            if (self::insertEditedMessageRequest($edited_message)) {
505
                $chat_id                 = $edited_message->getChat()->getId();
506
                $edited_message_local_id = self::$pdo->lastInsertId();
507
508
                return self::insertTelegramUpdate(
509
                    $update_id,
510
                    $chat_id,
511
                    null,
512
                    null,
513
                    null,
514
                    null,
515
                    $edited_message_local_id
516
                );
517
            }
518
        }
519
520
        return false;
521
    }
522
523
    /**
524
     * Insert inline query request into database
525
     *
526
     * @param \Longman\TelegramBot\Entities\InlineQuery $inline_query
527
     *
528
     * @return bool If the insert was successful
529
     * @throws \Longman\TelegramBot\Exception\TelegramException
530
     */
531 View Code Duplication
    public static function insertInlineQueryRequest(InlineQuery $inline_query)
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...
532
    {
533
        if (!self::isDbConnected()) {
534
            return false;
535
        }
536
537
        try {
538
            $sth = self::$pdo->prepare('
539
                INSERT IGNORE INTO `' . TB_INLINE_QUERY . '`
540
                (`id`, `user_id`, `location`, `query`, `offset`, `created_at`)
541
                VALUES
542
                (:inline_query_id, :user_id, :location, :query, :param_offset, :created_at)
543
            ');
544
545
            $date            = self::getTimestamp();
546
            $inline_query_id = $inline_query->getId();
547
            $from            = $inline_query->getFrom();
548
            $user_id         = null;
549
            if ($from instanceof User) {
550
                $user_id = $from->getId();
551
                self::insertUser($from, $date);
552
            }
553
554
            $location = $inline_query->getLocation();
555
            $query    = $inline_query->getQuery();
556
            $offset   = $inline_query->getOffset();
557
558
            $sth->bindParam(':inline_query_id', $inline_query_id, PDO::PARAM_INT);
559
            $sth->bindParam(':user_id', $user_id, PDO::PARAM_INT);
560
            $sth->bindParam(':location', $location, PDO::PARAM_STR);
561
            $sth->bindParam(':query', $query, PDO::PARAM_STR);
562
            $sth->bindParam(':param_offset', $offset, PDO::PARAM_STR);
563
            $sth->bindParam(':created_at', $date, PDO::PARAM_STR);
564
565
            return $sth->execute();
566
        } catch (PDOException $e) {
567
            throw new TelegramException($e->getMessage());
568
        }
569
    }
570
571
    /**
572
     * Insert chosen inline result request into database
573
     *
574
     * @param \Longman\TelegramBot\Entities\ChosenInlineResult $chosen_inline_result
575
     *
576
     * @return bool If the insert was successful
577
     * @throws \Longman\TelegramBot\Exception\TelegramException
578
     */
579 View Code Duplication
    public static function insertChosenInlineResultRequest(ChosenInlineResult $chosen_inline_result)
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...
580
    {
581
        if (!self::isDbConnected()) {
582
            return false;
583
        }
584
585
        try {
586
            $sth = self::$pdo->prepare('
587
                INSERT INTO `' . TB_CHOSEN_INLINE_RESULT . '`
588
                (`result_id`, `user_id`, `location`, `inline_message_id`, `query`, `created_at`)
589
                VALUES
590
                (:result_id, :user_id, :location, :inline_message_id, :query, :created_at)
591
            ');
592
593
            $date      = self::getTimestamp();
594
            $result_id = $chosen_inline_result->getResultId();
595
            $from      = $chosen_inline_result->getFrom();
596
            $user_id   = null;
597
            if ($from instanceof User) {
598
                $user_id = $from->getId();
599
                self::insertUser($from, $date);
600
            }
601
602
            $location          = $chosen_inline_result->getLocation();
603
            $inline_message_id = $chosen_inline_result->getInlineMessageId();
604
            $query             = $chosen_inline_result->getQuery();
605
606
            $sth->bindParam(':result_id', $result_id, PDO::PARAM_STR);
607
            $sth->bindParam(':user_id', $user_id, PDO::PARAM_INT);
608
            $sth->bindParam(':location', $location, PDO::PARAM_INT);
609
            $sth->bindParam(':inline_message_id', $inline_message_id, PDO::PARAM_STR);
610
            $sth->bindParam(':query', $query, PDO::PARAM_STR);
611
            $sth->bindParam(':created_at', $date, PDO::PARAM_STR);
612
613
            return $sth->execute();
614
        } catch (PDOException $e) {
615
            throw new TelegramException($e->getMessage());
616
        }
617
    }
618
619
    /**
620
     * Insert callback query request into database
621
     *
622
     * @param \Longman\TelegramBot\Entities\CallbackQuery $callback_query
623
     *
624
     * @return bool If the insert was successful
625
     * @throws \Longman\TelegramBot\Exception\TelegramException
626
     */
627
    public static function insertCallbackQueryRequest(CallbackQuery $callback_query)
628
    {
629
        if (!self::isDbConnected()) {
630
            return false;
631
        }
632
633
        try {
634
            $sth = self::$pdo->prepare('
635
                INSERT IGNORE INTO `' . TB_CALLBACK_QUERY . '`
636
                (`id`, `user_id`, `chat_id`, `message_id`, `inline_message_id`, `data`, `created_at`)
637
                VALUES
638
                (:callback_query_id, :user_id, :chat_id, :message_id, :inline_message_id, :data, :created_at)
639
            ');
640
641
            $date              = self::getTimestamp();
642
            $callback_query_id = $callback_query->getId();
643
            $from              = $callback_query->getFrom();
644
            $user_id           = null;
645
            if ($from instanceof User) {
646
                $user_id = $from->getId();
647
                self::insertUser($from, $date);
648
            }
649
650
            $message    = $callback_query->getMessage();
651
            $chat_id    = null;
652
            $message_id = null;
653
            if ($message instanceof Message) {
654
                $chat_id    = $message->getChat()->getId();
655
                $message_id = $message->getMessageId();
656
657
                $is_message = self::$pdo->query('
658
                    SELECT *
659
                    FROM `' . TB_MESSAGE . '`
660
                    WHERE `id` = ' . $message_id . '
661
                      AND `chat_id` = ' . $chat_id . '
662
                    LIMIT 1
663
                ')->rowCount();
664
665
                if ($is_message) {
666
                    self::insertEditedMessageRequest($message);
667
                } else {
668
                    self::insertMessageRequest($message);
669
                }
670
            }
671
672
            $inline_message_id = $callback_query->getInlineMessageId();
673
            $data              = $callback_query->getData();
674
675
            $sth->bindParam(':callback_query_id', $callback_query_id, PDO::PARAM_INT);
676
            $sth->bindParam(':user_id', $user_id, PDO::PARAM_INT);
677
            $sth->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
678
            $sth->bindParam(':message_id', $message_id, PDO::PARAM_INT);
679
            $sth->bindParam(':inline_message_id', $inline_message_id, PDO::PARAM_STR);
680
            $sth->bindParam(':data', $data, PDO::PARAM_STR);
681
            $sth->bindParam(':created_at', $date, PDO::PARAM_STR);
682
683
            return $sth->execute();
684
        } catch (PDOException $e) {
685
            throw new TelegramException($e->getMessage());
686
        }
687
    }
688
689
    /**
690
     * Insert Message request in db
691
     *
692
     * @param \Longman\TelegramBot\Entities\Message $message
693
     *
694
     * @return bool If the insert was successful
695
     * @throws \Longman\TelegramBot\Exception\TelegramException
696
     */
697 6
    public static function insertMessageRequest(Message $message)
698
    {
699 6
        if (!self::isDbConnected()) {
700
            return false;
701
        }
702
703 6
        $from = $message->getFrom();
704 6
        $chat = $message->getChat();
705
706 6
        $chat_id = $chat->getId();
707
708 6
        $date = self::getTimestamp($message->getDate());
709
710 6
        $forward_from       = $message->getForwardFrom();
711 6
        $forward_from_chat  = $message->getForwardFromChat();
712 6
        $photo              = self::entitiesArrayToJson($message->getPhoto(), '');
713 6
        $entities           = self::entitiesArrayToJson($message->getEntities(), null);
714 6
        $new_chat_member    = $message->getNewChatMember();
715 6
        $new_chat_photo     = self::entitiesArrayToJson($message->getNewChatPhoto(), '');
716 6
        $left_chat_member   = $message->getLeftChatMember();
717 6
        $migrate_to_chat_id = $message->getMigrateToChatId();
718
719
        //Insert chat, update chat id in case it migrated
720 6
        self::insertChat($chat, $date, $migrate_to_chat_id);
721
722
        //Insert user and the relation with the chat
723 6
        if (is_object($from)) {
724 6
            self::insertUser($from, $date, $chat);
725
        }
726
727
        //Insert the forwarded message user in users table
728 6
        if ($forward_from instanceof User) {
729
            $forward_date = self::getTimestamp($message->getForwardDate());
730
            self::insertUser($forward_from, $forward_date);
731
            $forward_from = $forward_from->getId();
732
        }
733
734 6
        if ($forward_from_chat instanceof Chat) {
735
            $forward_date = self::getTimestamp($message->getForwardDate());
736
            self::insertChat($forward_from_chat, $forward_date);
737
            $forward_from_chat = $forward_from_chat->getId();
738
        }
739
740
        //New and left chat member
741 6
        if ($new_chat_member instanceof User) {
742
            //Insert the new chat user
743
            self::insertUser($new_chat_member, $date, $chat);
744
            $new_chat_member = $new_chat_member->getId();
745
        } elseif ($left_chat_member instanceof User) {
746
            //Insert the left chat user
747
            self::insertUser($left_chat_member, $date, $chat);
748
            $left_chat_member = $left_chat_member->getId();
749
        }
750
751
        try {
752 6
            $sth = self::$pdo->prepare('
753 6
                INSERT IGNORE INTO `' . TB_MESSAGE . '`
754
                (
755
                    `id`, `user_id`, `chat_id`, `date`, `forward_from`, `forward_from_chat`,
756
                    `forward_date`, `reply_to_chat`, `reply_to_message`, `text`, `entities`, `audio`, `document`,
757
                    `photo`, `sticker`, `video`, `voice`, `caption`, `contact`,
758
                    `location`, `venue`, `new_chat_member`, `left_chat_member`,
759
                    `new_chat_title`,`new_chat_photo`, `delete_chat_photo`, `group_chat_created`,
760
                    `supergroup_chat_created`, `channel_chat_created`,
761
                    `migrate_from_chat_id`, `migrate_to_chat_id`, `pinned_message`
762
                ) VALUES (
763
                    :message_id, :user_id, :chat_id, :date, :forward_from, :forward_from_chat,
764
                    :forward_date, :reply_to_chat, :reply_to_message, :text, :entities, :audio, :document,
765
                    :photo, :sticker, :video, :voice, :caption, :contact,
766
                    :location, :venue, :new_chat_member, :left_chat_member,
767
                    :new_chat_title, :new_chat_photo, :delete_chat_photo, :group_chat_created,
768
                    :supergroup_chat_created, :channel_chat_created,
769
                    :migrate_from_chat_id, :migrate_to_chat_id, :pinned_message
770
                )
771 6
            ');
772
773 6
            $message_id = $message->getMessageId();
774
775 6
            if (is_object($from)) {
776 6
                $from_id = $from->getId();
777
            } else {
778
                $from_id = null;
779
            }
780
781 6
            $reply_to_message    = $message->getReplyToMessage();
782 6
            $reply_to_message_id = null;
783 6
            if ($reply_to_message instanceof ReplyToMessage) {
784
                $reply_to_message_id = $reply_to_message->getMessageId();
785
                // please notice that, as explained in the documentation, reply_to_message don't contain other
786
                // reply_to_message field so recursion deep is 1
787
                self::insertMessageRequest($reply_to_message);
788
            }
789
790 6
            $text                    = $message->getText();
791 6
            $audio                   = $message->getAudio();
792 6
            $document                = $message->getDocument();
793 6
            $sticker                 = $message->getSticker();
794 6
            $video                   = $message->getVideo();
795 6
            $voice                   = $message->getVoice();
796 6
            $caption                 = $message->getCaption();
797 6
            $contact                 = $message->getContact();
798 6
            $location                = $message->getLocation();
799 6
            $venue                   = $message->getVenue();
800 6
            $new_chat_title          = $message->getNewChatTitle();
801 6
            $delete_chat_photo       = $message->getDeleteChatPhoto();
802 6
            $group_chat_created      = $message->getGroupChatCreated();
803 6
            $supergroup_chat_created = $message->getSupergroupChatCreated();
804 6
            $channel_chat_created    = $message->getChannelChatCreated();
805 6
            $migrate_from_chat_id    = $message->getMigrateFromChatId();
806 6
            $migrate_to_chat_id      = $message->getMigrateToChatId();
807 6
            $pinned_message          = $message->getPinnedMessage();
808
809 6
            $sth->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
810 6
            $sth->bindParam(':message_id', $message_id, PDO::PARAM_INT);
811 6
            $sth->bindParam(':user_id', $from_id, PDO::PARAM_INT);
812 6
            $sth->bindParam(':date', $date, PDO::PARAM_STR);
813 6
            $sth->bindParam(':forward_from', $forward_from, PDO::PARAM_INT);
814 6
            $sth->bindParam(':forward_from_chat', $forward_from_chat, PDO::PARAM_INT);
815 6
            $sth->bindParam(':forward_date', $forward_date, PDO::PARAM_STR);
816
817 6
            $reply_to_chat_id = null;
818 6
            if ($reply_to_message_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $reply_to_message_id of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
819
                $reply_to_chat_id = $chat_id;
820
            }
821
822 6
            $sth->bindParam(':reply_to_chat', $reply_to_chat_id, PDO::PARAM_INT);
823 6
            $sth->bindParam(':reply_to_message', $reply_to_message_id, PDO::PARAM_INT);
824 6
            $sth->bindParam(':text', $text, PDO::PARAM_STR);
825 6
            $sth->bindParam(':entities', $entities, PDO::PARAM_STR);
826 6
            $sth->bindParam(':audio', $audio, PDO::PARAM_STR);
827 6
            $sth->bindParam(':document', $document, PDO::PARAM_STR);
828 6
            $sth->bindParam(':photo', $photo, PDO::PARAM_STR);
829 6
            $sth->bindParam(':sticker', $sticker, PDO::PARAM_STR);
830 6
            $sth->bindParam(':video', $video, PDO::PARAM_STR);
831 6
            $sth->bindParam(':voice', $voice, PDO::PARAM_STR);
832 6
            $sth->bindParam(':caption', $caption, PDO::PARAM_STR);
833 6
            $sth->bindParam(':contact', $contact, PDO::PARAM_STR);
834 6
            $sth->bindParam(':location', $location, PDO::PARAM_STR);
835 6
            $sth->bindParam(':venue', $venue, PDO::PARAM_STR);
836 6
            $sth->bindParam(':new_chat_member', $new_chat_member, PDO::PARAM_INT);
837 6
            $sth->bindParam(':left_chat_member', $left_chat_member, PDO::PARAM_INT);
838 6
            $sth->bindParam(':new_chat_title', $new_chat_title, PDO::PARAM_STR);
839 6
            $sth->bindParam(':new_chat_photo', $new_chat_photo, PDO::PARAM_STR);
840 6
            $sth->bindParam(':delete_chat_photo', $delete_chat_photo, PDO::PARAM_STR);
841 6
            $sth->bindParam(':group_chat_created', $group_chat_created, PDO::PARAM_STR);
842 6
            $sth->bindParam(':supergroup_chat_created', $supergroup_chat_created, PDO::PARAM_INT);
843 6
            $sth->bindParam(':channel_chat_created', $channel_chat_created, PDO::PARAM_INT);
844 6
            $sth->bindParam(':migrate_from_chat_id', $migrate_from_chat_id, PDO::PARAM_INT);
845 6
            $sth->bindParam(':migrate_to_chat_id', $migrate_to_chat_id, PDO::PARAM_INT);
846 6
            $sth->bindParam(':pinned_message', $pinned_message, PDO::PARAM_INT);
847
848 6
            return $sth->execute();
849
        } catch (PDOException $e) {
850
            throw new TelegramException($e->getMessage());
851
        }
852
    }
853
854
    /**
855
     * Insert Edited Message request in db
856
     *
857
     * @param \Longman\TelegramBot\Entities\Message $edited_message
858
     *
859
     * @return bool If the insert was successful
860
     * @throws \Longman\TelegramBot\Exception\TelegramException
861
     */
862
    public static function insertEditedMessageRequest(Message $edited_message)
863
    {
864
        if (!self::isDbConnected()) {
865
            return false;
866
        }
867
868
        $from = $edited_message->getFrom();
869
        $chat = $edited_message->getChat();
870
871
        $chat_id = $chat->getId();
872
873
        $edit_date = self::getTimestamp($edited_message->getEditDate());
874
875
        $entities = self::entitiesArrayToJson($edited_message->getEntities(), null);
876
877
        //Insert chat
878
        self::insertChat($chat, $edit_date);
879
880
        //Insert user and the relation with the chat
881
        if (is_object($from)) {
882
            self::insertUser($from, $edit_date, $chat);
883
        }
884
885
        try {
886
            $sth = self::$pdo->prepare('
887
                INSERT IGNORE INTO `' . TB_EDITED_MESSAGE . '`
888
                (`chat_id`, `message_id`, `user_id`, `edit_date`, `text`, `entities`, `caption`)
889
                VALUES
890
                (:chat_id, :message_id, :user_id, :date, :text, :entities, :caption)
891
            ');
892
893
            $message_id = $edited_message->getMessageId();
894
895
            if (is_object($from)) {
896
                $from_id = $from->getId();
897
            } else {
898
                $from_id = null;
899
            }
900
901
            $text    = $edited_message->getText();
902
            $caption = $edited_message->getCaption();
903
904
            $sth->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
905
            $sth->bindParam(':message_id', $message_id, PDO::PARAM_INT);
906
            $sth->bindParam(':user_id', $from_id, PDO::PARAM_INT);
907
            $sth->bindParam(':date', $edit_date, PDO::PARAM_STR);
908
            $sth->bindParam(':text', $text, PDO::PARAM_STR);
909
            $sth->bindParam(':entities', $entities, PDO::PARAM_STR);
910
            $sth->bindParam(':caption', $caption, PDO::PARAM_STR);
911
912
            return $sth->execute();
913
        } catch (PDOException $e) {
914
            throw new TelegramException($e->getMessage());
915
        }
916
    }
917
918
    /**
919
     * Select Group and/or single Chats
920
     *
921
     * @param bool   $select_groups
922
     * @param bool   $select_super_groups
923
     * @param bool   $select_users
924
     * @param string $date_from
925
     * @param string $date_to
926
     * @param int    $chat_id
927
     * @param string $text
928
     *
929
     * @return array|bool (Selected chats or false if invalid arguments)
930
     * @throws \Longman\TelegramBot\Exception\TelegramException
931
     */
932
    public static function selectChats(
933
        $select_groups = true,
934
        $select_super_groups = true,
935
        $select_users = true,
936
        $date_from = null,
937
        $date_to = null,
938
        $chat_id = null,
939
        $text = null
940
    ) {
941
        if (!self::isDbConnected()) {
942
            return false;
943
        }
944
945
        if (!$select_groups && !$select_users && !$select_super_groups) {
946
            return false;
947
        }
948
949
        try {
950
            $query = '
951
                SELECT * ,
952
                ' . TB_CHAT . '.`id` AS `chat_id`,
953
                ' . TB_CHAT . '.`created_at` AS `chat_created_at`,
954
                ' . TB_CHAT . '.`updated_at` AS `chat_updated_at`
955
            ';
956
            if ($select_users) {
957
                $query .= '
958
                    , ' . TB_USER . '.`id` AS `user_id`
959
                    FROM `' . TB_CHAT . '`
960
                    LEFT JOIN `' . TB_USER . '`
961
                    ON ' . TB_CHAT . '.`id`=' . TB_USER . '.`id`
962
                ';
963
            } else {
964
                $query .= 'FROM `' . TB_CHAT . '`';
965
            }
966
967
            //Building parts of query
968
            $where  = [];
969
            $tokens = [];
970
971
            if (!$select_groups || !$select_users || !$select_super_groups) {
972
                $chat_or_user = [];
973
974
                $select_groups && $chat_or_user[] = TB_CHAT . '.`type` = "group"';
975
                $select_super_groups && $chat_or_user[] = TB_CHAT . '.`type` = "supergroup"';
976
                $select_users && $chat_or_user[] = TB_CHAT . '.`type` = "private"';
977
978
                $where[] = '(' . implode(' OR ', $chat_or_user) . ')';
979
            }
980
981
            if (null !== $date_from) {
982
                $where[]              = TB_CHAT . '.`updated_at` >= :date_from';
983
                $tokens[':date_from'] = $date_from;
984
            }
985
986
            if (null !== $date_to) {
987
                $where[]            = TB_CHAT . '.`updated_at` <= :date_to';
988
                $tokens[':date_to'] = $date_to;
989
            }
990
991
            if (null !== $chat_id) {
992
                $where[]            = TB_CHAT . '.`id` = :chat_id';
993
                $tokens[':chat_id'] = $chat_id;
994
            }
995
996
            if (null !== $text) {
997
                if ($select_users) {
998
                    $where[] = '(
999
                        LOWER(' . TB_CHAT . '.`title`) LIKE :text
1000
                        OR LOWER(' . TB_USER . '.`first_name`) LIKE :text
1001
                        OR LOWER(' . TB_USER . '.`last_name`) LIKE :text
1002
                        OR LOWER(' . TB_USER . '.`username`) LIKE :text
1003
                    )';
1004
                } else {
1005
                    $where[] = 'LOWER(' . TB_CHAT . '.`title`) LIKE :text';
1006
                }
1007
                $tokens[':text'] = '%' . strtolower($text) . '%';
1008
            }
1009
1010
            if (!empty($where)) {
1011
                $query .= ' WHERE ' . implode(' AND ', $where);
1012
            }
1013
1014
            $query .= ' ORDER BY ' . TB_CHAT . '.`updated_at` ASC';
1015
1016
            $sth = self::$pdo->prepare($query);
1017
            $sth->execute($tokens);
1018
1019
            return $sth->fetchAll(PDO::FETCH_ASSOC);
1020
        } catch (PDOException $e) {
1021
            throw new TelegramException($e->getMessage());
1022
        }
1023
    }
1024
}
1025