Completed
Pull Request — develop (#377)
by Armando
02:33
created

DB::selectChats()   F

Complexity

Conditions 19
Paths 4754

Size

Total Lines 92
Code Lines 60

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 380

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 92
ccs 0
cts 51
cp 0
rs 2
cc 19
eloc 60
nc 4754
nop 7
crap 380

How to fix   Long Method    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
 * 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 = [];
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
     * Get the PDO object of the connected database
163
     *
164
     * @return \PDO
165
     */
166
    public static function getPdo()
167
    {
168
        return self::$pdo;
169
    }
170
171
    /**
172
     * Fetch update(s) from DB
173
     *
174
     * @param int $limit Limit the number of updates to fetch
175
     *
176
     * @return array|bool Fetched data or false if not connected
177
     * @throws \Longman\TelegramBot\Exception\TelegramException
178
     */
179 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...
180
    {
181
        if (!self::isDbConnected()) {
182
            return false;
183
        }
184
185
        try {
186
            $sql = '
187
                SELECT `id`
188
                FROM `' . TB_TELEGRAM_UPDATE . '`
189
                ORDER BY `id` DESC
190
            ';
191
192
            if ($limit !== null) {
193
                $sql .= 'LIMIT :limit';
194
            }
195
196
            $sth = self::$pdo->prepare($sql);
197
            $sth->bindParam(':limit', $limit, PDO::PARAM_INT);
198
            $sth->execute();
199
200
            return $sth->fetchAll(PDO::FETCH_ASSOC);
201
        } catch (PDOException $e) {
202
            throw new TelegramException($e->getMessage());
203
        }
204
    }
205
206
    /**
207
     * Fetch message(s) from DB
208
     *
209
     * @param int $limit Limit the number of messages to fetch
210
     *
211
     * @return array|bool Fetched data or false if not connected
212
     * @throws \Longman\TelegramBot\Exception\TelegramException
213
     */
214 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...
215
    {
216
        if (!self::isDbConnected()) {
217
            return false;
218
        }
219
220
        try {
221
            $sql = '
222
                SELECT *
223
                FROM `' . TB_MESSAGE . '`
224
                WHERE `update_id` != 0
225
                ORDER BY `message_id` DESC
226
            ';
227
228
            if ($limit !== null) {
229
                $sql .= 'LIMIT :limit';
230
            }
231
232
            $sth = self::$pdo->prepare($sql);
233
            $sth->bindParam(':limit', $limit, PDO::PARAM_INT);
234
            $sth->execute();
235
236
            return $sth->fetchAll(PDO::FETCH_ASSOC);
237
        } catch (PDOException $e) {
238
            throw new TelegramException($e->getMessage());
239
        }
240
    }
241
242
    /**
243
     * Convert from unix timestamp to timestamp
244
     *
245
     * @param int $time Unix timestamp (if null, current timestamp is used)
246
     *
247
     * @return string
248
     */
249 7
    protected static function getTimestamp($time = null)
250
    {
251 7
        if ($time === null) {
252 6
            $time = time();
253
        }
254
255 7
        return date('Y-m-d H:i:s', $time);
256
    }
257
258
    /**
259
     * Convert array of Entity items to a JSON array
260
     *
261
     * @todo Find a better way, as json_* functions are very heavy
262
     *
263
     * @param array|null $entities
264
     * @param mixed      $default
265
     *
266
     * @return mixed
267
     */
268 6
    public static function entitiesArrayToJson($entities, $default = null)
269
    {
270 6
        if (!is_array($entities)) {
271 6
            return $default;
272
        }
273
274
        //Convert each Entity item into an object based on its JSON reflection
275
        $json_entities = array_map(function ($entity) {
276
            return json_decode($entity, true);
277
        }, $entities);
278
279
        return json_encode($json_entities);
280
    }
281
282
    /**
283
     * Insert entry to telegram_update table
284
     *
285
     * @param int $id
286
     * @param int $chat_id
287
     * @param int $message_id
288
     * @param int $inline_query_id
289
     * @param int $chosen_inline_result_id
290
     * @param int $callback_query_id
291
     * @param int $edited_message_id
292
     *
293
     * @return bool If the insert was successful
294
     * @throws \Longman\TelegramBot\Exception\TelegramException
295
     */
296
    public static function insertTelegramUpdate(
297
        $id,
298
        $chat_id,
299
        $message_id,
300
        $inline_query_id,
301
        $chosen_inline_result_id,
302
        $callback_query_id,
303
        $edited_message_id
304
    ) {
305
        if ($message_id === null && $inline_query_id === null && $chosen_inline_result_id === null && $callback_query_id === null && $edited_message_id === null) {
306
            throw new TelegramException('message_id, inline_query_id, chosen_inline_result_id, callback_query_id, edited_message_id are all null');
307
        }
308
309
        if (!self::isDbConnected()) {
310
            return false;
311
        }
312
313
        try {
314
            $sth = self::$pdo->prepare('
315
                INSERT IGNORE INTO `' . TB_TELEGRAM_UPDATE . '`
316
                (`id`, `chat_id`, `message_id`, `inline_query_id`, `chosen_inline_result_id`, `callback_query_id`, `edited_message_id`)
317
                VALUES
318
                (:id, :chat_id, :message_id, :inline_query_id, :chosen_inline_result_id, :callback_query_id, :edited_message_id)
319
            ');
320
321
            $sth->bindParam(':id', $id, PDO::PARAM_INT);
322
            $sth->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
323
            $sth->bindParam(':message_id', $message_id, PDO::PARAM_INT);
324
            $sth->bindParam(':inline_query_id', $inline_query_id, PDO::PARAM_INT);
325
            $sth->bindParam(':chosen_inline_result_id', $chosen_inline_result_id, PDO::PARAM_INT);
326
            $sth->bindParam(':callback_query_id', $callback_query_id, PDO::PARAM_INT);
327
            $sth->bindParam(':edited_message_id', $edited_message_id, PDO::PARAM_INT);
328
329
            return $sth->execute();
330
        } catch (PDOException $e) {
331
            throw new TelegramException($e->getMessage());
332
        }
333
    }
334
335
    /**
336
     * Insert users and save their connection to chats
337
     *
338
     * @param  \Longman\TelegramBot\Entities\User $user
339
     * @param  string                             $date
340
     * @param  \Longman\TelegramBot\Entities\Chat $chat
341
     *
342
     * @return bool If the insert was successful
343
     * @throws \Longman\TelegramBot\Exception\TelegramException
344
     */
345 6
    public static function insertUser(User $user, $date, Chat $chat = null)
346
    {
347 6
        if (!self::isDbConnected()) {
348
            return false;
349
        }
350
351 6
        $user_id    = $user->getId();
352 6
        $username   = $user->getUsername();
353 6
        $first_name = $user->getFirstName();
354 6
        $last_name  = $user->getLastName();
355
356
        try {
357 6
            $sth = self::$pdo->prepare('
358 6
                INSERT INTO `' . TB_USER . '`
359
                (`id`, `username`, `first_name`, `last_name`, `created_at`, `updated_at`)
360
                VALUES
361
                (:id, :username, :first_name, :last_name, :date, :date)
362
                ON DUPLICATE KEY UPDATE
363
                    `username`   = :username,
364
                    `first_name` = :first_name,
365
                    `last_name`  = :last_name,
366
                    `updated_at` = :date
367 6
            ');
368
369 6
            $sth->bindParam(':id', $user_id, PDO::PARAM_INT);
370 6
            $sth->bindParam(':username', $username, PDO::PARAM_STR, 255);
371 6
            $sth->bindParam(':first_name', $first_name, PDO::PARAM_STR, 255);
372 6
            $sth->bindParam(':last_name', $last_name, PDO::PARAM_STR, 255);
373 6
            $sth->bindParam(':date', $date, PDO::PARAM_STR);
374
375 6
            $status = $sth->execute();
376
        } catch (PDOException $e) {
377
            throw new TelegramException($e->getMessage());
378
        }
379
380
        //insert also the relationship to the chat into user_chat table
381 6
        if ($chat instanceof Chat) {
382 6
            $chat_id = $chat->getId();
383
            try {
384 6
                $sth = self::$pdo->prepare('
385 6
                    INSERT IGNORE INTO `' . TB_USER_CHAT . '`
386
                    (`user_id`, `chat_id`)
387
                    VALUES
388
                    (:user_id, :chat_id)
389 6
                ');
390
391 6
                $sth->bindParam(':user_id', $user_id, PDO::PARAM_INT);
392 6
                $sth->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
393
394 6
                $status = $sth->execute();
395
            } catch (PDOException $e) {
396
                throw new TelegramException($e->getMessage());
397
            }
398
        }
399
400 6
        return $status;
401
    }
402
403
    /**
404
     * Insert chat
405
     *
406
     * @param  \Longman\TelegramBot\Entities\Chat $chat
407
     * @param  string                             $date
408
     * @param  int                                $migrate_to_chat_id
409
     *
410
     * @return bool If the insert was successful
411
     * @throws \Longman\TelegramBot\Exception\TelegramException
412
     */
413 6
    public static function insertChat(Chat $chat, $date, $migrate_to_chat_id = null)
414
    {
415 6
        if (!self::isDbConnected()) {
416
            return false;
417
        }
418
419 6
        $chat_id                             = $chat->getId();
420 6
        $chat_title                          = $chat->getTitle();
421 6
        $chat_type                           = $chat->getType();
422 6
        $chat_all_members_are_administrators = $chat->getAllMembersAreAdministrators();
423
424
        try {
425 6
            $sth = self::$pdo->prepare('
426 6
                INSERT IGNORE INTO `' . TB_CHAT . '`
427
                (`id`, `type`, `title`, `all_members_are_administrators`, `created_at` ,`updated_at`, `old_id`)
428
                VALUES
429
                (:id, :type, :title, :all_members_are_administrators, :date, :date, :oldid)
430
                ON DUPLICATE KEY UPDATE
431
                    `type`                           = :type,
432
                    `title`                          = :title,
433
                    `all_members_are_administrators` = :all_members_are_administrators,
434
                    `updated_at`                     = :date
435 6
            ');
436
437 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...
438
                $chat_type = 'supergroup';
439
440
                $sth->bindParam(':id', $migrate_to_chat_id, PDO::PARAM_INT);
441
                $sth->bindParam(':oldid', $chat_id, PDO::PARAM_INT);
442
            } else {
443 6
                $sth->bindParam(':id', $chat_id, PDO::PARAM_INT);
444 6
                $sth->bindParam(':oldid', $migrate_to_chat_id, PDO::PARAM_INT);
445
            }
446
447 6
            $sth->bindParam(':type', $chat_type, PDO::PARAM_INT);
448 6
            $sth->bindParam(':title', $chat_title, PDO::PARAM_STR, 255);
449 6
            $sth->bindParam(':all_members_are_administrators', $chat_all_members_are_administrators, PDO::PARAM_INT);
450 6
            $sth->bindParam(':date', $date, PDO::PARAM_STR);
451
452 6
            return $sth->execute();
453
        } catch (PDOException $e) {
454
            throw new TelegramException($e->getMessage());
455
        }
456
    }
457
458
    /**
459
     * Insert request into database
460
     *
461
     * @todo self::$pdo->lastInsertId() - unsafe usage if expected previous insert fails?
462
     *
463
     * @param \Longman\TelegramBot\Entities\Update $update
464
     *
465
     * @return bool
466
     * @throws \Longman\TelegramBot\Exception\TelegramException
467
     */
468
    public static function insertRequest(Update $update)
469
    {
470
        $update_id   = $update->getUpdateId();
471
        $update_type = $update->getUpdateType();
472
473
        if ($update_type === 'message') {
474
            $message = $update->getMessage();
475
476 View Code Duplication
            if (self::insertMessageRequest($message)) {
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...
477
                $message_id = $message->getMessageId();
478
                $chat_id    = $message->getChat()->getId();
479
480
                return self::insertTelegramUpdate($update_id, $chat_id, $message_id, null, null, null, null);
481
            }
482 View Code Duplication
        } elseif ($update_type === 'edited_message') {
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...
483
            $edited_message = $update->getEditedMessage();
484
485
            if (self::insertEditedMessageRequest($edited_message)) {
486
                $chat_id                 = $edited_message->getChat()->getId();
487
                $edited_message_local_id = self::$pdo->lastInsertId();
488
489
                return self::insertTelegramUpdate(
490
                    $update_id,
491
                    $chat_id,
492
                    null,
493
                    null,
494
                    null,
495
                    null,
496
                    $edited_message_local_id
497
                );
498
            }
499
        } elseif ($update_type === 'channel_post') {
500
            $channel_post = $update->getChannelPost();
501
502 View Code Duplication
            if (self::insertMessageRequest($channel_post)) {
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...
503
                $message_id = $channel_post->getMessageId();
504
                $chat_id    = $channel_post->getChat()->getId();
505
506
                return self::insertTelegramUpdate($update_id, $chat_id, $message_id, null, null, null, null);
507
            }
508 View Code Duplication
        } elseif ($update_type === 'edited_channel_post') {
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...
509
            $edited_channel_post = $update->getEditedChannelPost();
510
511
            if (self::insertEditedMessageRequest($edited_channel_post)) {
512
                $chat_id                      = $edited_channel_post->getChat()->getId();
513
                $edited_channel_post_local_id = self::$pdo->lastInsertId();
514
515
                return self::insertTelegramUpdate(
516
                    $update_id,
517
                    $chat_id,
518
                    null,
519
                    null,
520
                    null,
521
                    null,
522
                    $edited_channel_post_local_id
523
                );
524
            }
525
        } elseif ($update_type === 'inline_query') {
526
            $inline_query = $update->getInlineQuery();
527
528
            if (self::insertInlineQueryRequest($inline_query)) {
529
                $inline_query_id = $inline_query->getId();
530
531
                return self::insertTelegramUpdate($update_id, null, null, $inline_query_id, null, null, null);
532
            }
533
        } elseif ($update_type === 'chosen_inline_result') {
534
            $chosen_inline_result = $update->getChosenInlineResult();
535
536
            if (self::insertChosenInlineResultRequest($chosen_inline_result)) {
537
                $chosen_inline_result_local_id = self::$pdo->lastInsertId();
538
539
                return self::insertTelegramUpdate(
540
                    $update_id,
541
                    null,
542
                    null,
543
                    null,
544
                    $chosen_inline_result_local_id,
545
                    null,
546
                    null
547
                );
548
            }
549
        } elseif ($update_type === 'callback_query') {
550
            $callback_query = $update->getCallbackQuery();
551
552
            if (self::insertCallbackQueryRequest($callback_query)) {
553
                $callback_query_id = $callback_query->getId();
554
555
                return self::insertTelegramUpdate($update_id, null, null, null, null, $callback_query_id, null);
556
            }
557
        }
558
559
        return false;
560
    }
561
562
    /**
563
     * Insert inline query request into database
564
     *
565
     * @param \Longman\TelegramBot\Entities\InlineQuery $inline_query
566
     *
567
     * @return bool If the insert was successful
568
     * @throws \Longman\TelegramBot\Exception\TelegramException
569
     */
570 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...
571
    {
572
        if (!self::isDbConnected()) {
573
            return false;
574
        }
575
576
        try {
577
            $sth = self::$pdo->prepare('
578
                INSERT IGNORE INTO `' . TB_INLINE_QUERY . '`
579
                (`id`, `user_id`, `location`, `query`, `offset`, `created_at`)
580
                VALUES
581
                (:inline_query_id, :user_id, :location, :query, :param_offset, :created_at)
582
            ');
583
584
            $date            = self::getTimestamp();
585
            $inline_query_id = $inline_query->getId();
586
            $from            = $inline_query->getFrom();
587
            $user_id         = null;
588
            if ($from instanceof User) {
589
                $user_id = $from->getId();
590
                self::insertUser($from, $date);
591
            }
592
593
            $location = $inline_query->getLocation();
594
            $query    = $inline_query->getQuery();
595
            $offset   = $inline_query->getOffset();
596
597
            $sth->bindParam(':inline_query_id', $inline_query_id, PDO::PARAM_INT);
598
            $sth->bindParam(':user_id', $user_id, PDO::PARAM_INT);
599
            $sth->bindParam(':location', $location, PDO::PARAM_STR);
600
            $sth->bindParam(':query', $query, PDO::PARAM_STR);
601
            $sth->bindParam(':param_offset', $offset, PDO::PARAM_STR);
602
            $sth->bindParam(':created_at', $date, PDO::PARAM_STR);
603
604
            return $sth->execute();
605
        } catch (PDOException $e) {
606
            throw new TelegramException($e->getMessage());
607
        }
608
    }
609
610
    /**
611
     * Insert chosen inline result request into database
612
     *
613
     * @param \Longman\TelegramBot\Entities\ChosenInlineResult $chosen_inline_result
614
     *
615
     * @return bool If the insert was successful
616
     * @throws \Longman\TelegramBot\Exception\TelegramException
617
     */
618 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...
619
    {
620
        if (!self::isDbConnected()) {
621
            return false;
622
        }
623
624
        try {
625
            $sth = self::$pdo->prepare('
626
                INSERT INTO `' . TB_CHOSEN_INLINE_RESULT . '`
627
                (`result_id`, `user_id`, `location`, `inline_message_id`, `query`, `created_at`)
628
                VALUES
629
                (:result_id, :user_id, :location, :inline_message_id, :query, :created_at)
630
            ');
631
632
            $date      = self::getTimestamp();
633
            $result_id = $chosen_inline_result->getResultId();
634
            $from      = $chosen_inline_result->getFrom();
635
            $user_id   = null;
636
            if ($from instanceof User) {
637
                $user_id = $from->getId();
638
                self::insertUser($from, $date);
639
            }
640
641
            $location          = $chosen_inline_result->getLocation();
642
            $inline_message_id = $chosen_inline_result->getInlineMessageId();
643
            $query             = $chosen_inline_result->getQuery();
644
645
            $sth->bindParam(':result_id', $result_id, PDO::PARAM_STR);
646
            $sth->bindParam(':user_id', $user_id, PDO::PARAM_INT);
647
            $sth->bindParam(':location', $location, PDO::PARAM_STR);
648
            $sth->bindParam(':inline_message_id', $inline_message_id, PDO::PARAM_STR);
649
            $sth->bindParam(':query', $query, PDO::PARAM_STR);
650
            $sth->bindParam(':created_at', $date, PDO::PARAM_STR);
651
652
            return $sth->execute();
653
        } catch (PDOException $e) {
654
            throw new TelegramException($e->getMessage());
655
        }
656
    }
657
658
    /**
659
     * Insert callback query request into database
660
     *
661
     * @param \Longman\TelegramBot\Entities\CallbackQuery $callback_query
662
     *
663
     * @return bool If the insert was successful
664
     * @throws \Longman\TelegramBot\Exception\TelegramException
665
     */
666
    public static function insertCallbackQueryRequest(CallbackQuery $callback_query)
667
    {
668
        if (!self::isDbConnected()) {
669
            return false;
670
        }
671
672
        try {
673
            $sth = self::$pdo->prepare('
674
                INSERT IGNORE INTO `' . TB_CALLBACK_QUERY . '`
675
                (`id`, `user_id`, `chat_id`, `message_id`, `inline_message_id`, `data`, `created_at`)
676
                VALUES
677
                (:callback_query_id, :user_id, :chat_id, :message_id, :inline_message_id, :data, :created_at)
678
            ');
679
680
            $date              = self::getTimestamp();
681
            $callback_query_id = $callback_query->getId();
682
            $from              = $callback_query->getFrom();
683
            $user_id           = null;
684
            if ($from instanceof User) {
685
                $user_id = $from->getId();
686
                self::insertUser($from, $date);
687
            }
688
689
            $message    = $callback_query->getMessage();
690
            $chat_id    = null;
691
            $message_id = null;
692
            if ($message instanceof Message) {
693
                $chat_id    = $message->getChat()->getId();
694
                $message_id = $message->getMessageId();
695
696
                $is_message = self::$pdo->query('
697
                    SELECT *
698
                    FROM `' . TB_MESSAGE . '`
699
                    WHERE `id` = ' . $message_id . '
700
                      AND `chat_id` = ' . $chat_id . '
701
                    LIMIT 1
702
                ')->rowCount();
703
704
                if ($is_message) {
705
                    self::insertEditedMessageRequest($message);
706
                } else {
707
                    self::insertMessageRequest($message);
708
                }
709
            }
710
711
            $inline_message_id = $callback_query->getInlineMessageId();
712
            $data              = $callback_query->getData();
713
714
            $sth->bindParam(':callback_query_id', $callback_query_id, PDO::PARAM_INT);
715
            $sth->bindParam(':user_id', $user_id, PDO::PARAM_INT);
716
            $sth->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
717
            $sth->bindParam(':message_id', $message_id, PDO::PARAM_INT);
718
            $sth->bindParam(':inline_message_id', $inline_message_id, PDO::PARAM_STR);
719
            $sth->bindParam(':data', $data, PDO::PARAM_STR);
720
            $sth->bindParam(':created_at', $date, PDO::PARAM_STR);
721
722
            return $sth->execute();
723
        } catch (PDOException $e) {
724
            throw new TelegramException($e->getMessage());
725
        }
726
    }
727
728
    /**
729
     * Insert Message request in db
730
     *
731
     * @param \Longman\TelegramBot\Entities\Message $message
732
     *
733
     * @return bool If the insert was successful
734
     * @throws \Longman\TelegramBot\Exception\TelegramException
735
     */
736 6
    public static function insertMessageRequest(Message $message)
737
    {
738 6
        if (!self::isDbConnected()) {
739
            return false;
740
        }
741
742 6
        $from = $message->getFrom();
743 6
        $chat = $message->getChat();
744
745 6
        $chat_id = $chat->getId();
746
747 6
        $date = self::getTimestamp($message->getDate());
748
749 6
        $forward_from            = $message->getForwardFrom();
750 6
        $forward_from_chat       = $message->getForwardFromChat();
751 6
        $forward_from_message_id = $message->getForwardFromMessageId();
752 6
        $photo                   = self::entitiesArrayToJson($message->getPhoto(), '');
753 6
        $entities                = self::entitiesArrayToJson($message->getEntities(), null);
754 6
        $new_chat_member         = $message->getNewChatMember();
755 6
        $new_chat_photo          = self::entitiesArrayToJson($message->getNewChatPhoto(), '');
756 6
        $left_chat_member        = $message->getLeftChatMember();
757 6
        $migrate_to_chat_id      = $message->getMigrateToChatId();
758
759
        //Insert chat, update chat id in case it migrated
760 6
        self::insertChat($chat, $date, $migrate_to_chat_id);
761
762
        //Insert user and the relation with the chat
763 6
        if (is_object($from)) {
764 6
            self::insertUser($from, $date, $chat);
765
        }
766
767
        //Insert the forwarded message user in users table
768 6
        if ($forward_from instanceof User) {
769
            $forward_date = self::getTimestamp($message->getForwardDate());
770
            self::insertUser($forward_from, $forward_date);
771
            $forward_from = $forward_from->getId();
772
        }
773
774 6
        if ($forward_from_chat instanceof Chat) {
775
            $forward_date = self::getTimestamp($message->getForwardDate());
776
            self::insertChat($forward_from_chat, $forward_date);
777
            $forward_from_chat = $forward_from_chat->getId();
778
        }
779
780
        //New and left chat member
781 6
        if ($new_chat_member instanceof User) {
782
            //Insert the new chat user
783
            self::insertUser($new_chat_member, $date, $chat);
784
            $new_chat_member = $new_chat_member->getId();
785
        } elseif ($left_chat_member instanceof User) {
786
            //Insert the left chat user
787
            self::insertUser($left_chat_member, $date, $chat);
788
            $left_chat_member = $left_chat_member->getId();
789
        }
790
791
        try {
792 6
            $sth = self::$pdo->prepare('
793 6
                INSERT IGNORE INTO `' . TB_MESSAGE . '`
794
                (
795
                    `id`, `user_id`, `chat_id`, `date`, `forward_from`, `forward_from_chat`, `forward_from_message_id`,
796
                    `forward_date`, `reply_to_chat`, `reply_to_message`, `text`, `entities`, `audio`, `document`,
797
                    `photo`, `sticker`, `video`, `voice`, `caption`, `contact`,
798
                    `location`, `venue`, `new_chat_member`, `left_chat_member`,
799
                    `new_chat_title`,`new_chat_photo`, `delete_chat_photo`, `group_chat_created`,
800
                    `supergroup_chat_created`, `channel_chat_created`,
801
                    `migrate_from_chat_id`, `migrate_to_chat_id`, `pinned_message`
802
                ) VALUES (
803
                    :message_id, :user_id, :chat_id, :date, :forward_from, :forward_from_chat, :forward_from_message_id,
804
                    :forward_date, :reply_to_chat, :reply_to_message, :text, :entities, :audio, :document,
805
                    :photo, :sticker, :video, :voice, :caption, :contact,
806
                    :location, :venue, :new_chat_member, :left_chat_member,
807
                    :new_chat_title, :new_chat_photo, :delete_chat_photo, :group_chat_created,
808
                    :supergroup_chat_created, :channel_chat_created,
809
                    :migrate_from_chat_id, :migrate_to_chat_id, :pinned_message
810
                )
811 6
            ');
812
813 6
            $message_id = $message->getMessageId();
814
815 6
            if (is_object($from)) {
816 6
                $from_id = $from->getId();
817
            } else {
818
                $from_id = null;
819
            }
820
821 6
            $reply_to_message    = $message->getReplyToMessage();
822 6
            $reply_to_message_id = null;
823 6
            if ($reply_to_message instanceof ReplyToMessage) {
824
                $reply_to_message_id = $reply_to_message->getMessageId();
825
                // please notice that, as explained in the documentation, reply_to_message don't contain other
826
                // reply_to_message field so recursion deep is 1
827
                self::insertMessageRequest($reply_to_message);
828
            }
829
830 6
            $text                    = $message->getText();
831 6
            $audio                   = $message->getAudio();
832 6
            $document                = $message->getDocument();
833 6
            $sticker                 = $message->getSticker();
834 6
            $video                   = $message->getVideo();
835 6
            $voice                   = $message->getVoice();
836 6
            $caption                 = $message->getCaption();
837 6
            $contact                 = $message->getContact();
838 6
            $location                = $message->getLocation();
839 6
            $venue                   = $message->getVenue();
840 6
            $new_chat_title          = $message->getNewChatTitle();
841 6
            $delete_chat_photo       = $message->getDeleteChatPhoto();
842 6
            $group_chat_created      = $message->getGroupChatCreated();
843 6
            $supergroup_chat_created = $message->getSupergroupChatCreated();
844 6
            $channel_chat_created    = $message->getChannelChatCreated();
845 6
            $migrate_from_chat_id    = $message->getMigrateFromChatId();
846 6
            $migrate_to_chat_id      = $message->getMigrateToChatId();
847 6
            $pinned_message          = $message->getPinnedMessage();
848
849 6
            $sth->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
850 6
            $sth->bindParam(':message_id', $message_id, PDO::PARAM_INT);
851 6
            $sth->bindParam(':user_id', $from_id, PDO::PARAM_INT);
852 6
            $sth->bindParam(':date', $date, PDO::PARAM_STR);
853 6
            $sth->bindParam(':forward_from', $forward_from, PDO::PARAM_INT);
854 6
            $sth->bindParam(':forward_from_chat', $forward_from_chat, PDO::PARAM_INT);
855 6
            $sth->bindParam(':forward_from_message_id', $forward_from_message_id, PDO::PARAM_INT);
856 6
            $sth->bindParam(':forward_date', $forward_date, PDO::PARAM_STR);
857
858 6
            $reply_to_chat_id = null;
859 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...
860
                $reply_to_chat_id = $chat_id;
861
            }
862
863 6
            $sth->bindParam(':reply_to_chat', $reply_to_chat_id, PDO::PARAM_INT);
864 6
            $sth->bindParam(':reply_to_message', $reply_to_message_id, PDO::PARAM_INT);
865 6
            $sth->bindParam(':text', $text, PDO::PARAM_STR);
866 6
            $sth->bindParam(':entities', $entities, PDO::PARAM_STR);
867 6
            $sth->bindParam(':audio', $audio, PDO::PARAM_STR);
868 6
            $sth->bindParam(':document', $document, PDO::PARAM_STR);
869 6
            $sth->bindParam(':photo', $photo, PDO::PARAM_STR);
870 6
            $sth->bindParam(':sticker', $sticker, PDO::PARAM_STR);
871 6
            $sth->bindParam(':video', $video, PDO::PARAM_STR);
872 6
            $sth->bindParam(':voice', $voice, PDO::PARAM_STR);
873 6
            $sth->bindParam(':caption', $caption, PDO::PARAM_STR);
874 6
            $sth->bindParam(':contact', $contact, PDO::PARAM_STR);
875 6
            $sth->bindParam(':location', $location, PDO::PARAM_STR);
876 6
            $sth->bindParam(':venue', $venue, PDO::PARAM_STR);
877 6
            $sth->bindParam(':new_chat_member', $new_chat_member, PDO::PARAM_INT);
878 6
            $sth->bindParam(':left_chat_member', $left_chat_member, PDO::PARAM_INT);
879 6
            $sth->bindParam(':new_chat_title', $new_chat_title, PDO::PARAM_STR);
880 6
            $sth->bindParam(':new_chat_photo', $new_chat_photo, PDO::PARAM_STR);
881 6
            $sth->bindParam(':delete_chat_photo', $delete_chat_photo, PDO::PARAM_INT);
882 6
            $sth->bindParam(':group_chat_created', $group_chat_created, PDO::PARAM_INT);
883 6
            $sth->bindParam(':supergroup_chat_created', $supergroup_chat_created, PDO::PARAM_INT);
884 6
            $sth->bindParam(':channel_chat_created', $channel_chat_created, PDO::PARAM_INT);
885 6
            $sth->bindParam(':migrate_from_chat_id', $migrate_from_chat_id, PDO::PARAM_INT);
886 6
            $sth->bindParam(':migrate_to_chat_id', $migrate_to_chat_id, PDO::PARAM_INT);
887 6
            $sth->bindParam(':pinned_message', $pinned_message, PDO::PARAM_STR);
888
889 6
            return $sth->execute();
890
        } catch (PDOException $e) {
891
            throw new TelegramException($e->getMessage());
892
        }
893
    }
894
895
    /**
896
     * Insert Edited Message request in db
897
     *
898
     * @param \Longman\TelegramBot\Entities\Message $edited_message
899
     *
900
     * @return bool If the insert was successful
901
     * @throws \Longman\TelegramBot\Exception\TelegramException
902
     */
903
    public static function insertEditedMessageRequest(Message $edited_message)
904
    {
905
        if (!self::isDbConnected()) {
906
            return false;
907
        }
908
909
        $from = $edited_message->getFrom();
910
        $chat = $edited_message->getChat();
911
912
        $chat_id = $chat->getId();
913
914
        $edit_date = self::getTimestamp($edited_message->getEditDate());
915
916
        $entities = self::entitiesArrayToJson($edited_message->getEntities(), null);
917
918
        //Insert chat
919
        self::insertChat($chat, $edit_date);
920
921
        //Insert user and the relation with the chat
922
        if (is_object($from)) {
923
            self::insertUser($from, $edit_date, $chat);
924
        }
925
926
        try {
927
            $sth = self::$pdo->prepare('
928
                INSERT IGNORE INTO `' . TB_EDITED_MESSAGE . '`
929
                (`chat_id`, `message_id`, `user_id`, `edit_date`, `text`, `entities`, `caption`)
930
                VALUES
931
                (:chat_id, :message_id, :user_id, :date, :text, :entities, :caption)
932
            ');
933
934
            $message_id = $edited_message->getMessageId();
935
936
            if (is_object($from)) {
937
                $from_id = $from->getId();
938
            } else {
939
                $from_id = null;
940
            }
941
942
            $text    = $edited_message->getText();
943
            $caption = $edited_message->getCaption();
944
945
            $sth->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
946
            $sth->bindParam(':message_id', $message_id, PDO::PARAM_INT);
947
            $sth->bindParam(':user_id', $from_id, PDO::PARAM_INT);
948
            $sth->bindParam(':date', $edit_date, PDO::PARAM_STR);
949
            $sth->bindParam(':text', $text, PDO::PARAM_STR);
950
            $sth->bindParam(':entities', $entities, PDO::PARAM_STR);
951
            $sth->bindParam(':caption', $caption, PDO::PARAM_STR);
952
953
            return $sth->execute();
954
        } catch (PDOException $e) {
955
            throw new TelegramException($e->getMessage());
956
        }
957
    }
958
959
    /**
960
     * Select Group and/or single Chats
961
     *
962
     * @param bool   $select_groups
963
     * @param bool   $select_super_groups
964
     * @param bool   $select_users
965
     * @param string $date_from
966
     * @param string $date_to
967
     * @param int    $chat_id
968
     * @param string $text
969
     *
970
     * @return array|bool (Selected chats or false if invalid arguments)
971
     * @throws \Longman\TelegramBot\Exception\TelegramException
972
     */
973
    public static function selectChats(
974
        $select_groups = true,
975
        $select_super_groups = true,
976
        $select_users = true,
977
        $date_from = null,
978
        $date_to = null,
979
        $chat_id = null,
980
        $text = null
981
    ) {
982
        if (!self::isDbConnected()) {
983
            return false;
984
        }
985
986
        if (!$select_groups && !$select_users && !$select_super_groups) {
987
            return false;
988
        }
989
990
        try {
991
            $query = '
992
                SELECT * ,
993
                ' . TB_CHAT . '.`id` AS `chat_id`,
994
                ' . TB_CHAT . '.`created_at` AS `chat_created_at`,
995
                ' . TB_CHAT . '.`updated_at` AS `chat_updated_at`
996
            ';
997
            if ($select_users) {
998
                $query .= '
999
                    , ' . TB_USER . '.`id` AS `user_id`
1000
                    FROM `' . TB_CHAT . '`
1001
                    LEFT JOIN `' . TB_USER . '`
1002
                    ON ' . TB_CHAT . '.`id`=' . TB_USER . '.`id`
1003
                ';
1004
            } else {
1005
                $query .= 'FROM `' . TB_CHAT . '`';
1006
            }
1007
1008
            //Building parts of query
1009
            $where  = [];
1010
            $tokens = [];
1011
1012
            if (!$select_groups || !$select_users || !$select_super_groups) {
1013
                $chat_or_user = [];
1014
1015
                $select_groups && $chat_or_user[] = TB_CHAT . '.`type` = "group"';
1016
                $select_super_groups && $chat_or_user[] = TB_CHAT . '.`type` = "supergroup"';
1017
                $select_users && $chat_or_user[] = TB_CHAT . '.`type` = "private"';
1018
1019
                $where[] = '(' . implode(' OR ', $chat_or_user) . ')';
1020
            }
1021
1022
            if (null !== $date_from) {
1023
                $where[]              = TB_CHAT . '.`updated_at` >= :date_from';
1024
                $tokens[':date_from'] = $date_from;
1025
            }
1026
1027
            if (null !== $date_to) {
1028
                $where[]            = TB_CHAT . '.`updated_at` <= :date_to';
1029
                $tokens[':date_to'] = $date_to;
1030
            }
1031
1032
            if (null !== $chat_id) {
1033
                $where[]            = TB_CHAT . '.`id` = :chat_id';
1034
                $tokens[':chat_id'] = $chat_id;
1035
            }
1036
1037
            if (null !== $text) {
1038
                if ($select_users) {
1039
                    $where[] = '(
1040
                        LOWER(' . TB_CHAT . '.`title`) LIKE :text
1041
                        OR LOWER(' . TB_USER . '.`first_name`) LIKE :text
1042
                        OR LOWER(' . TB_USER . '.`last_name`) LIKE :text
1043
                        OR LOWER(' . TB_USER . '.`username`) LIKE :text
1044
                    )';
1045
                } else {
1046
                    $where[] = 'LOWER(' . TB_CHAT . '.`title`) LIKE :text';
1047
                }
1048
                $tokens[':text'] = '%' . strtolower($text) . '%';
1049
            }
1050
1051
            if (!empty($where)) {
1052
                $query .= ' WHERE ' . implode(' AND ', $where);
1053
            }
1054
1055
            $query .= ' ORDER BY ' . TB_CHAT . '.`updated_at` ASC';
1056
1057
            $sth = self::$pdo->prepare($query);
1058
            $sth->execute($tokens);
1059
1060
            return $sth->fetchAll(PDO::FETCH_ASSOC);
1061
        } catch (PDOException $e) {
1062
            throw new TelegramException($e->getMessage());
1063
        }
1064
    }
1065
}
1066