Completed
Branch feature/improve-code (a8c279)
by Avtandil
06:09
created

DB::selectMessages()   B

Complexity

Conditions 4
Paths 12

Size

Total Lines 26
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 26
ccs 0
cts 16
cp 0
rs 8.5806
cc 4
eloc 16
nc 12
nop 1
crap 20
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\Update;
20
use Longman\TelegramBot\Entities\User;
21
use Longman\TelegramBot\Exception\TelegramException;
22
use PDO;
23
use PDOException;
24
25
class DB
26
{
27
    /**
28
     * MySQL credentials
29
     *
30
     * @var array
31
     */
32
    static protected $mysql_credentials = [];
33
34
    /**
35
     * PDO object
36
     *
37
     * @var PDO
38
     */
39
    static protected $pdo;
40
41
    /**
42
     * Table prefix
43
     *
44
     * @var string
45
     */
46
    static protected $table_prefix;
47
48
    /**
49
     * Telegram class object
50
     *
51
     * @var \Longman\TelegramBot\Telegram
52
     */
53
    static protected $telegram;
54
55
    /**
56
     * Initialize
57
     *
58
     * @param array                         $credentials  Database connection details
59
     * @param \Longman\TelegramBot\Telegram $telegram     Telegram object to connect with this object
60
     * @param string                        $table_prefix Table prefix
61
     * @param string                        $encoding     Database character encoding
62
     *
63
     * @return PDO PDO database object
64
     * @throws \Longman\TelegramBot\Exception\TelegramException
65
     */
66 9
    public static function initialize(
67
        array $credentials,
68
        Telegram $telegram,
69
        $table_prefix = null,
70
        $encoding = 'utf8mb4'
71
    ) {
72 9
        if (empty($credentials)) {
73
            throw new TelegramException('MySQL credentials not provided!');
74
        }
75
76 9
        $dsn     = 'mysql:host=' . $credentials['host'] . ';dbname=' . $credentials['database'];
77 9
        $options = [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . $encoding];
78
        try {
79 9
            $pdo = new PDO($dsn, $credentials['user'], $credentials['password'], $options);
80 9
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
81 9
        } catch (PDOException $e) {
82
            throw new TelegramException($e->getMessage());
83
        }
84
85 9
        self::$pdo               = $pdo;
86 9
        self::$telegram          = $telegram;
87 9
        self::$mysql_credentials = $credentials;
88 9
        self::$table_prefix      = $table_prefix;
89
90 9
        self::defineTable();
91
92 9
        return self::$pdo;
93
    }
94
95
    /**
96
     * External Initialize
97
     *
98
     * Let you use the class with an external already existing Pdo Mysql connection.
99
     *
100
     * @param PDO                           $external_pdo_connection PDO database object
101
     * @param \Longman\TelegramBot\Telegram $telegram                Telegram object to connect with this object
102
     * @param string                        $table_prefix            Table prefix
103
     *
104
     * @return PDO PDO database object
105
     * @throws \Longman\TelegramBot\Exception\TelegramException
106
     */
107
    public static function externalInitialize($external_pdo_connection, Telegram $telegram, $table_prefix = null)
108
    {
109
        if (empty($external_pdo_connection)) {
110
            throw new TelegramException('MySQL external connection not provided!');
111
        }
112
113
        self::$pdo               = $external_pdo_connection;
114
        self::$telegram          = $telegram;
115
        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...
116
        self::$table_prefix      = $table_prefix;
117
118
        self::defineTable();
119
120
        return self::$pdo;
121
    }
122
123
    /**
124
     * Define all the table with the proper prefix
125
     */
126 9
    protected static function defineTable()
127
    {
128 9
        if (!defined('TB_TELEGRAM_UPDATE')) {
129 1
            define('TB_TELEGRAM_UPDATE', self::$table_prefix . 'telegram_update');
130 1
        }
131 9
        if (!defined('TB_MESSAGE')) {
132 1
            define('TB_MESSAGE', self::$table_prefix . 'message');
133 1
        }
134 9
        if (!defined('TB_EDITED_MESSAGE')) {
135 1
            define('TB_EDITED_MESSAGE', self::$table_prefix . 'edited_message');
136 1
        }
137 9
        if (!defined('TB_INLINE_QUERY')) {
138 1
            define('TB_INLINE_QUERY', self::$table_prefix . 'inline_query');
139 1
        }
140 9
        if (!defined('TB_CHOSEN_INLINE_RESULT')) {
141 1
            define('TB_CHOSEN_INLINE_RESULT', self::$table_prefix . 'chosen_inline_result');
142 1
        }
143 9
        if (!defined('TB_CALLBACK_QUERY')) {
144 1
            define('TB_CALLBACK_QUERY', self::$table_prefix . 'callback_query');
145 1
        }
146 9
        if (!defined('TB_USER')) {
147 1
            define('TB_USER', self::$table_prefix . 'user');
148 1
        }
149 9
        if (!defined('TB_CHAT')) {
150 1
            define('TB_CHAT', self::$table_prefix . 'chat');
151 1
        }
152 9
        if (!defined('TB_USER_CHAT')) {
153 1
            define('TB_USER_CHAT', self::$table_prefix . 'user_chat');
154 1
        }
155 9
    }
156
157
    /**
158
     * Check if database connection has been created
159
     *
160
     * @return bool
161
     */
162 9
    public static function isDbConnected()
163
    {
164 9
        if (empty(self::$pdo)) {
165
            return false;
166
        } else {
167 9
            return true;
168
        }
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
    public static function selectTelegramUpdate($limit = null)
180
    {
181
        if (!self::isDbConnected()) {
182
            return false;
183
        }
184
185
        try {
186
            $query = 'SELECT `id` FROM `' . TB_TELEGRAM_UPDATE . '` ';
187
            $query .= 'ORDER BY `id` DESC';
188
189
            if (!is_null($limit)) {
190
                $query .= ' LIMIT :limit ';
191
            }
192
193
            $sth_select_telegram_update = self::$pdo->prepare($query);
194
            $sth_select_telegram_update->bindParam(':limit', $limit, PDO::PARAM_INT);
195
            $sth_select_telegram_update->execute();
196
            $results = $sth_select_telegram_update->fetchAll(PDO::FETCH_ASSOC);
197
        } catch (PDOException $e) {
198
            throw new TelegramException($e->getMessage());
199
        }
200
201
        return $results;
202
    }
203
204
    /**
205
     * Fetch message(s) from DB
206
     *
207
     * @param int $limit Limit the number of messages to fetch
208
     *
209
     * @return array|bool Fetched data or false if not connected
210
     * @throws \Longman\TelegramBot\Exception\TelegramException
211
     */
212
    public static function selectMessages($limit = null)
213
    {
214
        if (!self::isDbConnected()) {
215
            return false;
216
        }
217
218
        try {
219
            //message table
220
            $query = 'SELECT * FROM `' . TB_MESSAGE . '` ';
221
            $query .= 'WHERE ' . TB_MESSAGE . '.`update_id` != 0 ';
222
            $query .= 'ORDER BY ' . TB_MESSAGE . '.`message_id` DESC';
223
224
            if (!is_null($limit)) {
225
                $query .= ' LIMIT :limit ';
226
            }
227
228
            $sth = self::$pdo->prepare($query);
229
            $sth->bindParam(':limit', $limit, PDO::PARAM_INT);
230
            $sth->execute();
231
            $results = $sth->fetchAll(PDO::FETCH_ASSOC);
232
        } catch (PDOException $e) {
233
            throw new TelegramException($e->getMessage());
234
        }
235
236
        return $results;
237
    }
238
239
    /**
240
     * Convert from unix timestamp to timestamp
241
     *
242
     * @param int $time Unix timestamp
243
     *
244
     * @return null|string Timestamp if a time has been passed, else null
245
     */
246 7
    protected static function getTimestamp($time = null)
247
    {
248 7
        if (is_null($time)) {
249 6
            return date('Y-m-d H:i:s', time());
250
        }
251 6
        return date('Y-m-d H:i:s', $time);
252
    }
253
254
    /**
255
     * Insert entry to telegram_update table
256
     *
257
     * @param int $id
258
     * @param int $chat_id
259
     * @param int $message_id
260
     * @param int $inline_query_id
261
     * @param int $chosen_inline_result_id
262
     * @param int $callback_query_id
263
     * @param int $edited_message_id
264
     *
265
     * @return bool If the insert was successful
266
     * @throws \Longman\TelegramBot\Exception\TelegramException
267
     */
268
    public static function insertTelegramUpdate(
269
        $id,
270
        $chat_id,
271
        $message_id,
272
        $inline_query_id,
273
        $chosen_inline_result_id,
274
        $callback_query_id,
275
        $edited_message_id
276
    ) {
277
        if (is_null($message_id) && is_null($inline_query_id) && is_null($chosen_inline_result_id) && is_null($callback_query_id) && is_null($edited_message_id)) {
278
            throw new TelegramException('message_id, inline_query_id, chosen_inline_result_id, callback_query_id, edited_message_id are all null');
279
        }
280
281
        if (!self::isDbConnected()) {
282
            return false;
283
        }
284
285
        try {
286
            $sth_insert_telegram_update = self::$pdo->prepare('INSERT IGNORE INTO `' . TB_TELEGRAM_UPDATE . '`
287
                (
288
                `id`, `chat_id`, `message_id`, `inline_query_id`, `chosen_inline_result_id`, `callback_query_id`, `edited_message_id`
289
                )
290
                VALUES (
291
                :id, :chat_id, :message_id, :inline_query_id, :chosen_inline_result_id, :callback_query_id, :edited_message_id
292
                )
293
                ');
294
295
            $sth_insert_telegram_update->bindParam(':id', $id, PDO::PARAM_INT);
296
            $sth_insert_telegram_update->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
297
            $sth_insert_telegram_update->bindParam(':message_id', $message_id, PDO::PARAM_INT);
298
            $sth_insert_telegram_update->bindParam(':inline_query_id', $inline_query_id, PDO::PARAM_INT);
299
            $sth_insert_telegram_update->bindParam(':chosen_inline_result_id', $chosen_inline_result_id,
300
                                                   PDO::PARAM_INT);
301
            $sth_insert_telegram_update->bindParam(':callback_query_id', $callback_query_id, PDO::PARAM_INT);
302
            $sth_insert_telegram_update->bindParam(':edited_message_id', $edited_message_id, PDO::PARAM_INT);
303
304
            return $sth_insert_telegram_update->execute();
305
        } catch (PDOException $e) {
306
            throw new TelegramException($e->getMessage());
307
        }
308
    }
309
310
    /**
311
     * Insert users and save their connection to chats
312
     *
313
     * @param  \Longman\TelegramBot\Entities\User $user
314
     * @param  string                             $date
315
     * @param  \Longman\TelegramBot\Entities\Chat $chat
316
     *
317
     * @return bool If the insert was successful
318
     * @throws \Longman\TelegramBot\Exception\TelegramException
319
     */
320 6
    public static function insertUser(User $user, $date, Chat $chat = null)
321
    {
322 6
        if (!self::isDbConnected()) {
323
            return false;
324
        }
325
326 6
        $user_id    = $user->getId();
327 6
        $username   = $user->getUsername();
328 6
        $first_name = $user->getFirstName();
329 6
        $last_name  = $user->getLastName();
330
331
        try {
332 6
            $sth1 = self::$pdo->prepare('INSERT INTO `' . TB_USER . '`
333
                (
334
                `id`, `username`, `first_name`, `last_name`, `created_at`, `updated_at`
335
                )
336
                VALUES (
337
                :id, :username, :first_name, :last_name, :date, :date
338
                )
339
                ON DUPLICATE KEY UPDATE `username`=:username, `first_name`=:first_name,
340
                `last_name`=:last_name, `updated_at`=:date
341 6
                ');
342
343 6
            $sth1->bindParam(':id', $user_id, PDO::PARAM_INT);
344 6
            $sth1->bindParam(':username', $username, PDO::PARAM_STR, 255);
345 6
            $sth1->bindParam(':first_name', $first_name, PDO::PARAM_STR, 255);
346 6
            $sth1->bindParam(':last_name', $last_name, PDO::PARAM_STR, 255);
347 6
            $sth1->bindParam(':date', $date, PDO::PARAM_STR);
348
349 6
            $status = $sth1->execute();
350 6
        } catch (PDOException $e) {
351
            throw new TelegramException($e->getMessage());
352
        }
353
354
        //insert also the relationship to the chat into user_chat table
355 6
        if (!is_null($chat)) {
356 6
            $chat_id = $chat->getId();
357
            try {
358 6
                $sth3 = self::$pdo->prepare('INSERT IGNORE INTO `' . TB_USER_CHAT . '`
359
                    (
360
                    `user_id`, `chat_id`
361
                    )
362
                    VALUES (
363
                    :user_id, :chat_id
364 6
                    )');
365
366 6
                $sth3->bindParam(':user_id', $user_id, PDO::PARAM_INT);
367 6
                $sth3->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
368
369 6
                $status = $sth3->execute();
370 6
            } catch (PDOException $e) {
371
                throw new TelegramException($e->getMessage());
372
            }
373 6
        }
374
375 6
        return $status;
376
    }
377
378
    /**
379
     * Insert chat
380
     *
381
     * @param  \Longman\TelegramBot\Entities\Chat $chat
382
     * @param  string                             $date
383
     * @param  int                                $migrate_to_chat_id
384
     *
385
     * @return bool If the insert was successful
386
     * @throws \Longman\TelegramBot\Exception\TelegramException
387
     */
388 6
    public static function insertChat(Chat $chat, $date, $migrate_to_chat_id = null)
389
    {
390 6
        if (!self::isDbConnected()) {
391
            return false;
392
        }
393
394 6
        $chat_id    = $chat->getId();
395 6
        $chat_title = $chat->getTitle();
396 6
        $type       = $chat->getType();
397
398
        try {
399 6
            $sth2 = self::$pdo->prepare('INSERT INTO `' . TB_CHAT . '`
400
                (
401
                `id`, `type`, `title`, `created_at` ,`updated_at`, `old_id`
402
                )
403
                VALUES (
404
                :id, :type, :title, :date, :date, :oldid
405
                )
406
                ON DUPLICATE KEY UPDATE `type`=:type, `title`=:title, `updated_at`=:date
407 6
                ');
408
409 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...
410
                $type = 'supergroup';
411
412
                $sth2->bindParam(':id', $migrate_to_chat_id, PDO::PARAM_INT);
413
                $sth2->bindParam(':oldid', $chat_id, PDO::PARAM_INT);
414
            } else {
415 6
                $sth2->bindParam(':id', $chat_id, PDO::PARAM_INT);
416 6
                $sth2->bindParam(':oldid', $migrate_to_chat_id, PDO::PARAM_INT);
417
            }
418
419 6
            $sth2->bindParam(':type', $type, PDO::PARAM_INT);
420 6
            $sth2->bindParam(':title', $chat_title, PDO::PARAM_STR, 255);
421 6
            $sth2->bindParam(':date', $date, PDO::PARAM_STR);
422
423 6
            return $sth2->execute();
424
        } catch (PDOException $e) {
425
            throw new TelegramException($e->getMessage());
426
        }
427
    }
428
429
    /**
430
     * Insert request into database
431
     *
432
     * @todo self::$pdo->lastInsertId() - unsafe usage if expected previous insert fails?
433
     *
434
     * @param \Longman\TelegramBot\Entities\Update $update
435
     *
436
     * @return bool
437
     */
438
    public static function insertRequest(Update $update)
439
    {
440
        $update_id = $update->getUpdateId();
441
        if ($update->getUpdateType() == 'message') {
442
            $message = $update->getMessage();
443
444
            if (self::insertMessageRequest($message)) {
445
                $message_id = $message->getMessageId();
446
                $chat_id    = $message->getChat()->getId();
447
                return self::insertTelegramUpdate($update_id, $chat_id, $message_id, null, null, null, null);
448
            }
449 View Code Duplication
        } elseif ($update->getUpdateType() == '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...
450
            $inline_query = $update->getInlineQuery();
451
452
            if (self::insertInlineQueryRequest($inline_query)) {
453
                $inline_query_id = $inline_query->getId();
454
                return self::insertTelegramUpdate($update_id, null, null, $inline_query_id, null, null, null);
455
            }
456
        } elseif ($update->getUpdateType() == 'chosen_inline_result') {
457
            $chosen_inline_result = $update->getChosenInlineResult();
458
459
            if (self::insertChosenInlineResultRequest($chosen_inline_result)) {
460
                $chosen_inline_result_local_id = self::$pdo->lastInsertId();
461
                return self::insertTelegramUpdate($update_id, null, null, null, $chosen_inline_result_local_id, null,
462
                                                  null);
463
            }
464 View Code Duplication
        } elseif ($update->getUpdateType() == '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...
465
            $callback_query = $update->getCallbackQuery();
466
467
            if (self::insertCallbackQueryRequest($callback_query)) {
468
                $callback_query_id = $callback_query->getId();
469
                return self::insertTelegramUpdate($update_id, null, null, null, null, $callback_query_id, null);
470
            }
471
        } elseif ($update->getUpdateType() == 'edited_message') {
472
            $edited_message = $update->getEditedMessage();
473
474
            if (self::insertEditedMessageRequest($edited_message)) {
475
                $chat_id                 = $edited_message->getChat()->getId();
476
                $edited_message_local_id = self::$pdo->lastInsertId();
477
                return self::insertTelegramUpdate($update_id, $chat_id, null, null, null, null,
478
                                                  $edited_message_local_id);
479
            }
480
        }
481
482
        return false;
483
    }
484
485
    /**
486
     * Insert inline query request into database
487
     *
488
     * @param \Longman\TelegramBot\Entities\InlineQuery $inline_query
489
     *
490
     * @return bool If the insert was successful
491
     * @throws \Longman\TelegramBot\Exception\TelegramException
492
     */
493 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...
494
    {
495
        if (!self::isDbConnected()) {
496
            return false;
497
        }
498
499
        try {
500
            $mysql_query = 'INSERT IGNORE INTO `' . TB_INLINE_QUERY . '`
501
                (
502
                `id`, `user_id`, `location`, `query`, `offset`, `created_at`
503
                )
504
                VALUES (
505
                :inline_query_id, :user_id, :location, :query, :param_offset, :created_at
506
                )';
507
508
            $sth_insert_inline_query = self::$pdo->prepare($mysql_query);
509
510
            $date            = self::getTimestamp(time());
511
            $inline_query_id = $inline_query->getId();
512
            $from            = $inline_query->getFrom();
513
            $user_id         = null;
514
            if (is_object($from)) {
515
                $user_id = $from->getId();
516
                self::insertUser($from, $date);
517
            }
518
519
            $location = $inline_query->getLocation();
520
            $query    = $inline_query->getQuery();
521
            $offset   = $inline_query->getOffset();
522
523
            $sth_insert_inline_query->bindParam(':inline_query_id', $inline_query_id, PDO::PARAM_INT);
524
            $sth_insert_inline_query->bindParam(':user_id', $user_id, PDO::PARAM_INT);
525
            $sth_insert_inline_query->bindParam(':location', $location, PDO::PARAM_STR);
526
            $sth_insert_inline_query->bindParam(':query', $query, PDO::PARAM_STR);
527
            $sth_insert_inline_query->bindParam(':param_offset', $offset, PDO::PARAM_STR);
528
            $sth_insert_inline_query->bindParam(':created_at', $date, PDO::PARAM_STR);
529
530
            return $sth_insert_inline_query->execute();
531
        } catch (PDOException $e) {
532
            throw new TelegramException($e->getMessage());
533
        }
534
    }
535
536
    /**
537
     * Insert chosen inline result request into database
538
     *
539
     * @param \Longman\TelegramBot\Entities\ChosenInlineResult $chosen_inline_result
540
     *
541
     * @return bool If the insert was successful
542
     * @throws \Longman\TelegramBot\Exception\TelegramException
543
     */
544 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...
545
    {
546
        if (!self::isDbConnected()) {
547
            return false;
548
        }
549
550
        try {
551
            $mysql_query = 'INSERT INTO `' . TB_CHOSEN_INLINE_RESULT . '`
552
                    (
553
                    `result_id`, `user_id`, `location`, `inline_message_id`, `query`, `created_at`
554
                    )
555
                    VALUES (
556
                    :result_id, :user_id, :location, :inline_message_id, :query, :created_at
557
                    )';
558
559
            $sth_insert_chosen_inline_result = self::$pdo->prepare($mysql_query);
560
561
            $date      = self::getTimestamp(time());
562
            $result_id = $chosen_inline_result->getResultId();
563
            $from      = $chosen_inline_result->getFrom();
564
            $user_id   = null;
565
            if (is_object($from)) {
566
                $user_id = $from->getId();
567
                self::insertUser($from, $date);
568
            }
569
570
            $location          = $chosen_inline_result->getLocation();
571
            $inline_message_id = $chosen_inline_result->getInlineMessageId();
572
            $query             = $chosen_inline_result->getQuery();
573
574
            $sth_insert_chosen_inline_result->bindParam(':result_id', $result_id, PDO::PARAM_STR);
575
            $sth_insert_chosen_inline_result->bindParam(':user_id', $user_id, PDO::PARAM_INT);
576
            $sth_insert_chosen_inline_result->bindParam(':location', $location, PDO::PARAM_INT);
577
            $sth_insert_chosen_inline_result->bindParam(':inline_message_id', $inline_message_id, PDO::PARAM_STR);
578
            $sth_insert_chosen_inline_result->bindParam(':query', $query, PDO::PARAM_STR);
579
            $sth_insert_chosen_inline_result->bindParam(':created_at', $date, PDO::PARAM_STR);
580
581
            return $sth_insert_chosen_inline_result->execute();
582
        } catch (PDOException $e) {
583
            throw new TelegramException($e->getMessage());
584
        }
585
    }
586
587
    /**
588
     * Insert callback query request into database
589
     *
590
     * @param \Longman\TelegramBot\Entities\CallbackQuery $callback_query
591
     *
592
     * @return bool If the insert was successful
593
     * @throws \Longman\TelegramBot\Exception\TelegramException
594
     */
595
    public static function insertCallbackQueryRequest(CallbackQuery $callback_query)
596
    {
597
        if (!self::isDbConnected()) {
598
            return false;
599
        }
600
601
        try {
602
            $mysql_query = 'INSERT IGNORE INTO `' . TB_CALLBACK_QUERY . '`
603
                (
604
                `id`, `user_id`, `chat_id`, `message_id`, `inline_message_id`, `data`, `created_at`
605
                )
606
                VALUES (
607
                :callback_query_id, :user_id, :chat_id, :message_id, :inline_message_id, :data, :created_at
608
                )';
609
610
            $sth_insert_callback_query = self::$pdo->prepare($mysql_query);
611
612
            $date = self::getTimestamp(time());
613
614
            $callback_query_id = $callback_query->getId();
615
            $from              = $callback_query->getFrom();
616
            $user_id           = null;
617
            if (is_object($from)) {
618
                $user_id = $from->getId();
619
                self::insertUser($from, $date);
620
            }
621
622
            $message    = $callback_query->getMessage();
623
            $chat_id    = null;
624
            $message_id = null;
625
            if ($message) {
626
                $chat_id    = $message->getChat()->getId();
627
                $message_id = $message->getMessageId();
628
629
                $sth = self::$pdo->prepare('SELECT * FROM `' . TB_MESSAGE . '`
630
                    WHERE `id` = ' . $message_id . ' AND `chat_id` = ' . $chat_id . ' LIMIT 1');
631
                $sth->execute();
632
633
                if ($sth->rowCount() > 0) {
634
                    self::insertEditedMessageRequest($message);
635
                } else {
636
                    self::insertMessageRequest($message);
637
                }
638
            }
639
640
            $inline_message_id = $callback_query->getInlineMessageId();
641
            $data              = $callback_query->getData();
642
643
            $sth_insert_callback_query->bindParam(':callback_query_id', $callback_query_id, PDO::PARAM_INT);
644
            $sth_insert_callback_query->bindParam(':user_id', $user_id, PDO::PARAM_INT);
645
            $sth_insert_callback_query->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
646
            $sth_insert_callback_query->bindParam(':message_id', $message_id, PDO::PARAM_INT);
647
            $sth_insert_callback_query->bindParam(':inline_message_id', $inline_message_id, PDO::PARAM_STR);
648
            $sth_insert_callback_query->bindParam(':data', $data, PDO::PARAM_STR);
649
            $sth_insert_callback_query->bindParam(':created_at', $date, PDO::PARAM_STR);
650
651
            return $sth_insert_callback_query->execute();
652
        } catch (PDOException $e) {
653
            throw new TelegramException($e->getMessage());
654
        }
655
    }
656
657
    /**
658
     * Insert Message request in db
659
     *
660
     * @param \Longman\TelegramBot\Entities\Message $message
661
     *
662
     * @return bool If the insert was successful
663
     * @throws \Longman\TelegramBot\Exception\TelegramException
664
     */
665 6
    public static function insertMessageRequest(Message $message)
666
    {
667 6
        if (!self::isDbConnected()) {
668
            return false;
669
        }
670
671 6
        $from = $message->getFrom();
672 6
        $chat = $message->getChat();
673
674 6
        $chat_id = $chat->getId();
675
676 6
        $date = self::getTimestamp($message->getDate());
677
678 6
        $forward_from       = $message->getForwardFrom();
679 6
        $forward_from_chat  = $message->getForwardFromChat();
680 6
        $photo              = $message->getPhoto();
681 6
        $entities           = $message->getEntities();
682 6
        $new_chat_member    = $message->getNewChatMember();
683 6
        $new_chat_photo     = $message->getNewChatPhoto();
684 6
        $left_chat_member   = $message->getLeftChatMember();
685 6
        $migrate_to_chat_id = $message->getMigrateToChatId();
686
687
        //Insert chat, update chat id in case it migrated
688 6
        self::insertChat($chat, $date, $migrate_to_chat_id);
689
690
        //Insert user and the relation with the chat
691 6
        self::insertUser($from, $date, $chat);
692
693
        //Insert the forwarded message user in users table
694 6
        if (is_object($forward_from)) {
695
            $forward_date = self::getTimestamp($message->getForwardDate());
696
            self::insertUser($forward_from, $forward_date);
697
            $forward_from = $forward_from->getId();
698
        }
699
700 6
        if (is_object($forward_from_chat)) {
701
            $forward_date = self::getTimestamp($message->getForwardDate());
702
            self::insertChat($forward_from_chat, $forward_date);
703
            $forward_from_chat = $forward_from_chat->getId();
704
        }
705
706
        //New and left chat member
707 6
        if ($new_chat_member) {
708
            //Insert the new chat user
709
            self::insertUser($new_chat_member, $date, $chat);
710
            $new_chat_member = $new_chat_member->getId();
711 6
        } elseif ($left_chat_member) {
712
            //Insert the left chat user
713
            self::insertUser($left_chat_member, $date, $chat);
714
            $left_chat_member = $left_chat_member->getId();
715
        }
716
717
        try {
718 6
            $sth = self::$pdo->prepare('INSERT IGNORE INTO `' . TB_MESSAGE . '`
719
                (
720
                `id`, `user_id`, `chat_id`, `date`, `forward_from`, `forward_from_chat`,
721
                `forward_date`, `reply_to_chat`, `reply_to_message`, `text`, `entities`, `audio`, `document`,
722
                `photo`, `sticker`, `video`, `voice`, `caption`, `contact`,
723
                `location`, `venue`, `new_chat_member`, `left_chat_member`,
724
                `new_chat_title`,`new_chat_photo`, `delete_chat_photo`, `group_chat_created`,
725
                `supergroup_chat_created`, `channel_chat_created`,
726
                `migrate_from_chat_id`, `migrate_to_chat_id`, `pinned_message`
727
                )
728
                VALUES (
729
                :message_id, :user_id, :chat_id, :date, :forward_from, :forward_from_chat,
730
                :forward_date, :reply_to_chat, :reply_to_message, :text, :entities, :audio, :document,
731
                :photo, :sticker, :video, :voice, :caption, :contact,
732
                :location, :venue, :new_chat_member, :left_chat_member,
733
                :new_chat_title, :new_chat_photo, :delete_chat_photo, :group_chat_created,
734
                :supergroup_chat_created, :channel_chat_created,
735
                :migrate_from_chat_id, :migrate_to_chat_id, :pinned_message
736
                )
737 6
                ');
738
739 6
            $message_id = $message->getMessageId();
740 6
            $from_id    = $from->getId();
741
742 6
            $reply_to_message    = $message->getReplyToMessage();
743 6
            $reply_to_message_id = null;
744 6
            if (is_object($reply_to_message)) {
745
                $reply_to_message_id = $reply_to_message->getMessageId();
746
                // please notice that, as explained in the documentation, reply_to_message don't contain other
747
                // reply_to_message field so recursion deep is 1
748
                self::insertMessageRequest($reply_to_message);
749
            }
750
751 6
            $text                    = $message->getText();
752 6
            $audio                   = $message->getAudio();
753 6
            $document                = $message->getDocument();
754 6
            $sticker                 = $message->getSticker();
755 6
            $video                   = $message->getVideo();
756 6
            $voice                   = $message->getVoice();
757 6
            $caption                 = $message->getCaption();
758 6
            $contact                 = $message->getContact();
759 6
            $location                = $message->getLocation();
760 6
            $venue                   = $message->getVenue();
761 6
            $new_chat_title          = $message->getNewChatTitle();
762 6
            $delete_chat_photo       = $message->getDeleteChatPhoto();
763 6
            $group_chat_created      = $message->getGroupChatCreated();
764 6
            $supergroup_chat_created = $message->getSupergroupChatCreated();
765 6
            $channel_chat_created    = $message->getChannelChatCreated();
766 6
            $migrate_from_chat_id    = $message->getMigrateFromChatId();
767 6
            $migrate_to_chat_id      = $message->getMigrateToChatId();
768 6
            $pinned_message          = $message->getPinnedMessage();
769
770 6
            $sth->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
771 6
            $sth->bindParam(':message_id', $message_id, PDO::PARAM_INT);
772 6
            $sth->bindParam(':user_id', $from_id, PDO::PARAM_INT);
773 6
            $sth->bindParam(':date', $date, PDO::PARAM_STR);
774 6
            $sth->bindParam(':forward_from', $forward_from, PDO::PARAM_INT);
775 6
            $sth->bindParam(':forward_from_chat', $forward_from_chat, PDO::PARAM_INT);
776 6
            $sth->bindParam(':forward_date', $forward_date, PDO::PARAM_STR);
777
778 6
            $reply_chat_id = null;
779 6
            if ($reply_to_message_id) {
780
                $reply_chat_id = $chat_id;
781
            }
782
783 6
            $var = [];
784 6 View Code Duplication
            if (is_array($entities)) {
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...
785
                foreach ($entities as $elm) {
786
                    $var[] = json_decode($elm, true);
787
                }
788
789
                $entities = json_encode($var);
790
            } else {
791 6
                $entities = null;
792
            }
793
794 6
            $sth->bindParam(':reply_to_chat', $reply_chat_id, PDO::PARAM_INT);
795 6
            $sth->bindParam(':reply_to_message', $reply_to_message_id, PDO::PARAM_INT);
796 6
            $sth->bindParam(':text', $text, PDO::PARAM_STR);
797 6
            $sth->bindParam(':entities', $entities, PDO::PARAM_STR);
798 6
            $sth->bindParam(':audio', $audio, PDO::PARAM_STR);
799 6
            $sth->bindParam(':document', $document, PDO::PARAM_STR);
800
801 6
            $var = [];
802 6 View Code Duplication
            if (is_array($photo)) {
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...
803
                foreach ($photo as $elm) {
804
                    $var[] = json_decode($elm, true);
805
                }
806
807
                $photo = json_encode($var);
808
            } else {
809 6
                $photo = '';
810
            }
811
812 6
            $sth->bindParam(':photo', $photo, PDO::PARAM_STR);
813 6
            $sth->bindParam(':sticker', $sticker, PDO::PARAM_STR);
814 6
            $sth->bindParam(':video', $video, PDO::PARAM_STR);
815 6
            $sth->bindParam(':voice', $voice, PDO::PARAM_STR);
816 6
            $sth->bindParam(':caption', $caption, PDO::PARAM_STR);
817 6
            $sth->bindParam(':contact', $contact, PDO::PARAM_STR);
818 6
            $sth->bindParam(':location', $location, PDO::PARAM_STR);
819 6
            $sth->bindParam(':venue', $venue, PDO::PARAM_STR);
820 6
            $sth->bindParam(':new_chat_member', $new_chat_member, PDO::PARAM_INT);
821 6
            $sth->bindParam(':left_chat_member', $left_chat_member, PDO::PARAM_INT);
822 6
            $sth->bindParam(':new_chat_title', $new_chat_title, PDO::PARAM_STR);
823
824
            //Array of PhotoSize
825 6
            $var = [];
826 6 View Code Duplication
            if (is_array($new_chat_photo)) {
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...
827
                foreach ($new_chat_photo as $elm) {
828
                    $var[] = json_decode($elm, true);
829
                }
830
831
                $new_chat_photo = json_encode($var);
832
            } else {
833 6
                $new_chat_photo = '';
834
            }
835
836 6
            $sth->bindParam(':new_chat_photo', $new_chat_photo, PDO::PARAM_STR);
837 6
            $sth->bindParam(':delete_chat_photo', $delete_chat_photo, PDO::PARAM_STR);
838 6
            $sth->bindParam(':group_chat_created', $group_chat_created, PDO::PARAM_STR);
839 6
            $sth->bindParam(':supergroup_chat_created', $supergroup_chat_created, PDO::PARAM_INT);
840 6
            $sth->bindParam(':channel_chat_created', $channel_chat_created, PDO::PARAM_INT);
841 6
            $sth->bindParam(':migrate_from_chat_id', $migrate_from_chat_id, PDO::PARAM_INT);
842 6
            $sth->bindParam(':migrate_to_chat_id', $migrate_to_chat_id, PDO::PARAM_INT);
843 6
            $sth->bindParam(':pinned_message', $pinned_message, PDO::PARAM_INT);
844
845 6
            return $sth->execute();
846
        } catch (PDOException $e) {
847
            throw new TelegramException($e->getMessage());
848
        }
849
    }
850
851
    /**
852
     * Insert Edited Message request in db
853
     *
854
     * @param \Longman\TelegramBot\Entities\Message $edited_message
855
     *
856
     * @return bool If the insert was successful
857
     * @throws \Longman\TelegramBot\Exception\TelegramException
858
     */
859
    public static function insertEditedMessageRequest(Message $edited_message)
860
    {
861
        if (!self::isDbConnected()) {
862
            return false;
863
        }
864
865
        $from = $edited_message->getFrom();
866
        $chat = $edited_message->getChat();
867
868
        $chat_id = $chat->getId();
869
870
        $edit_date = self::getTimestamp($edited_message->getEditDate());
871
872
        $entities = $edited_message->getEntities();
873
874
        //Insert chat
875
        self::insertChat($chat, $edit_date);
876
877
        //Insert user and the relation with the chat
878
        self::insertUser($from, $edit_date, $chat);
879
880
        try {
881
            $sth = self::$pdo->prepare('INSERT INTO `' . TB_EDITED_MESSAGE . '`
882
                (
883
                `chat_id`, `message_id`, `user_id`, `edit_date`, `text`, `entities`, `caption`
884
                )
885
                VALUES (
886
                :chat_id, :message_id, :user_id, :date, :text, :entities, :caption
887
                )');
888
889
            $message_id = $edited_message->getMessageId();
890
            $from_id    = $from->getId();
891
892
            $text    = $edited_message->getText();
893
            $caption = $edited_message->getCaption();
894
895
            $sth->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
896
            $sth->bindParam(':message_id', $message_id, PDO::PARAM_INT);
897
            $sth->bindParam(':user_id', $from_id, PDO::PARAM_INT);
898
            $sth->bindParam(':date', $edit_date, PDO::PARAM_STR);
899
900
            $var = [];
901 View Code Duplication
            if (is_array($entities)) {
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...
902
                foreach ($entities as $elm) {
903
                    $var[] = json_decode($elm, true);
904
                }
905
906
                $entities = json_encode($var);
907
            } else {
908
                $entities = null;
909
            }
910
911
            $sth->bindParam(':text', $text, PDO::PARAM_STR);
912
            $sth->bindParam(':entities', $entities, PDO::PARAM_STR);
913
            $sth->bindParam(':caption', $caption, PDO::PARAM_STR);
914
915
            return $sth->execute();
916
        } catch (PDOException $e) {
917
            throw new TelegramException($e->getMessage());
918
        }
919
    }
920
921
    /**
922
     * Select Group and/or single Chats
923
     *
924
     * @param bool   $select_groups
925
     * @param bool   $select_super_groups
926
     * @param bool   $select_users
927
     * @param string $date_from
928
     * @param string $date_to
929
     * @param int    $chat_id
930
     * @param string $text
931
     *
932
     * @return array|bool (Selected chats or false if invalid arguments)
933
     * @throws \Longman\TelegramBot\Exception\TelegramException
934
     */
935
    public static function selectChats(
936
        $select_groups = true,
937
        $select_super_groups = true,
938
        $select_users = true,
939
        $date_from = null,
940
        $date_to = null,
941
        $chat_id = null,
942
        $text = null
943
    ) {
944
        if (!self::isDbConnected()) {
945
            return false;
946
        }
947
948
        if (!$select_groups && !$select_users && !$select_super_groups) {
949
            return false;
950
        }
951
952
        try {
953
            $query = 'SELECT * ,
954
                ' . TB_CHAT . '.`id` AS `chat_id`,
955
                ' . TB_CHAT . '.`created_at` AS `chat_created_at`,
956
                ' . TB_CHAT . '.`updated_at` AS `chat_updated_at`
957
                ' .
958
                (($select_users) ? ', ' . TB_USER . '.`id` AS `user_id` FROM `' . TB_CHAT . '` LEFT JOIN `' . TB_USER . '`
959
                ON ' . TB_CHAT . '.`id`=' . TB_USER . '.`id`' : 'FROM `' . TB_CHAT . '`');
960
961
            //Building parts of query
962
            $where  = [];
963
            $tokens = [];
964
965
            if (!$select_groups || !$select_users || !$select_super_groups) {
966
                $chat_or_user = '';
967
968
                if ($select_groups) {
969
                    $chat_or_user .= TB_CHAT . '.`type` = "group"';
970
                }
971
972
                if ($select_super_groups) {
973
                    if (!empty($chat_or_user)) {
974
                        $chat_or_user .= ' OR ';
975
                    }
976
977
                    $chat_or_user .= TB_CHAT . '.`type` = "supergroup"';
978
                }
979
980
                if ($select_users) {
981
                    if (!empty($chat_or_user)) {
982
                        $chat_or_user .= ' OR ';
983
                    }
984
985
                    $chat_or_user .= TB_CHAT . '.`type` = "private"';
986
                }
987
988
                $where[] = '(' . $chat_or_user . ')';
989
            }
990
991
            if (!is_null($date_from)) {
992
                $where[]              = TB_CHAT . '.`updated_at` >= :date_from';
993
                $tokens[':date_from'] = $date_from;
994
            }
995
996
            if (!is_null($date_to)) {
997
                $where[]            = TB_CHAT . '.`updated_at` <= :date_to';
998
                $tokens[':date_to'] = $date_to;
999
            }
1000
1001
            if (!is_null($chat_id)) {
1002
                $where[]            = TB_CHAT . '.`id` = :chat_id';
1003
                $tokens[':chat_id'] = $chat_id;
1004
            }
1005
1006
            if (!is_null($text)) {
1007
                if ($select_users) {
1008
                    $where[] = '(LOWER(' . TB_CHAT . '.`title`) LIKE :text OR LOWER(' . TB_USER . '.`first_name`) LIKE :text OR LOWER(' . TB_USER . '.`last_name`) LIKE :text OR LOWER(' . TB_USER . '.`username`) LIKE :text)';
1009
                } else {
1010
                    $where[] = 'LOWER(' . TB_CHAT . '.`title`) LIKE :text';
1011
                }
1012
1013
                $tokens[':text'] = '%' . strtolower($text) . '%';
1014
            }
1015
1016
            $a = 0;
1017
            foreach ($where as $part) {
1018
                if ($a) {
1019
                    $query .= ' AND ' . $part;
1020
                } else {
1021
                    $query .= ' WHERE ' . $part;
1022
                    ++$a;
1023
                }
1024
            }
1025
1026
            $query .= ' ORDER BY ' . TB_CHAT . '.`updated_at` ASC';
1027
1028
            $sth = self::$pdo->prepare($query);
1029
            $sth->execute($tokens);
1030
1031
            $result = $sth->fetchAll(PDO::FETCH_ASSOC);
1032
        } catch (PDOException $e) {
1033
            throw new TelegramException($e->getMessage());
1034
        }
1035
1036
        return $result;
1037
    }
1038
}
1039