Completed
Push — master ( 203d4a...ef9e39 )
by
unknown
04:46 queued 02:35
created

DB::defineTable()   F

Complexity

Conditions 10
Paths 512

Size

Total Lines 30
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
dl 0
loc 30
rs 3.2187
c 4
b 0
f 0
cc 10
eloc 19
nc 512
nop 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A DB::isDbConnected() 0 4 1

How to fix   Complexity   

Long Method

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

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

Commonly applied refactorings include:

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

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

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

Loading history...
120
        self::$table_prefix      = $table_prefix;
121
122
        self::defineTables();
123
124
        return self::$pdo;
125
    }
126
127
    /**
128
     * Define all the tables with the proper prefix
129
     */
130 9
    protected static function defineTables()
131
    {
132
        $tables = [
133 9
            'callback_query',
134
            'chat',
135
            'chosen_inline_result',
136
            'edited_message',
137
            'inline_query',
138
            'message',
139
            'telegram_update',
140
            'user',
141
            'user_chat',
142
        ];
143 9
        foreach ($tables as $table) {
144 9
            $table_name = 'TB_' . strtoupper($table);
145 9
            if (!defined($table_name)) {
146 9
                define($table_name, self::$table_prefix . $table);
147
            }
148
        }
149 9
    }
150
151
    /**
152
     * Check if database connection has been created
153
     *
154
     * @return bool
155
     */
156 9
    public static function isDbConnected()
157
    {
158 9
        return self::$pdo !== null;
159
    }
160
161
    /**
162
     * Fetch update(s) from DB
163
     *
164
     * @param int $limit Limit the number of updates to fetch
165
     *
166
     * @return array|bool Fetched data or false if not connected
167
     * @throws \Longman\TelegramBot\Exception\TelegramException
168
     */
169 View Code Duplication
    public static function selectTelegramUpdate($limit = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
170
    {
171
        if (!self::isDbConnected()) {
172
            return false;
173
        }
174
175
        try {
176
            $sql = '
177
                SELECT `id`
178
                FROM `' . TB_TELEGRAM_UPDATE . '`
179
                ORDER BY `id` DESC
180
            ';
181
182
            if ($limit !== null) {
183
                $sql .= 'LIMIT :limit';
184
            }
185
186
            $sth = self::$pdo->prepare($sql);
187
            $sth->bindParam(':limit', $limit, PDO::PARAM_INT);
188
            $sth->execute();
189
190
            return $sth->fetchAll(PDO::FETCH_ASSOC);
191
        } catch (PDOException $e) {
192
            throw new TelegramException($e->getMessage());
193
        }
194
    }
195
196
    /**
197
     * Fetch message(s) from DB
198
     *
199
     * @param int $limit Limit the number of messages to fetch
200
     *
201
     * @return array|bool Fetched data or false if not connected
202
     * @throws \Longman\TelegramBot\Exception\TelegramException
203
     */
204 View Code Duplication
    public static function selectMessages($limit = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
205
    {
206
        if (!self::isDbConnected()) {
207
            return false;
208
        }
209
210
        try {
211
            $sql = '
212
                SELECT *
213
                FROM `' . TB_MESSAGE . '`
214
                WHERE `update_id` != 0
215
                ORDER BY `message_id` DESC
216
            ';
217
218
            if ($limit !== null) {
219
                $sql .= 'LIMIT :limit';
220
            }
221
222
            $sth = self::$pdo->prepare($sql);
223
            $sth->bindParam(':limit', $limit, PDO::PARAM_INT);
224
            $sth->execute();
225
226
            return $sth->fetchAll(PDO::FETCH_ASSOC);
227
        } catch (PDOException $e) {
228
            throw new TelegramException($e->getMessage());
229
        }
230
    }
231
232
    /**
233
     * Convert from unix timestamp to timestamp
234
     *
235
     * @param int $time Unix timestamp (if null, current timestamp is used)
236
     *
237
     * @return string
238
     */
239 7
    protected static function getTimestamp($time = null)
240
    {
241 7
        if ($time === null) {
242 6
            $time = time();
243
        }
244
245 7
        return date('Y-m-d H:i:s', $time);
246
    }
247
248
    /**
249
     * Convert array of Entity items to a JSON array
250
     *
251
     * @todo Find a better way, as json_* functions are very heavy
252
     *
253
     * @param array|null $entities
254
     * @param mixed      $default
255
     *
256
     * @return mixed
257
     */
258 6
    public static function entitiesArrayToJson($entities, $default = null)
259
    {
260 6
        if (!is_array($entities)) {
261 6
            return $default;
262
        }
263
264
        //Convert each Entity item into an object based on its JSON reflection
265
        $json_entities = array_map(function ($entity) {
266
            return json_decode($entity, true);
267
        }, $entities);
268
269
        return json_encode($json_entities);
270
    }
271
272
    /**
273
     * Insert entry to telegram_update table
274
     *
275
     * @param int $id
276
     * @param int $chat_id
277
     * @param int $message_id
278
     * @param int $inline_query_id
279
     * @param int $chosen_inline_result_id
280
     * @param int $callback_query_id
281
     * @param int $edited_message_id
282
     *
283
     * @return bool If the insert was successful
284
     * @throws \Longman\TelegramBot\Exception\TelegramException
285
     */
286
    public static function insertTelegramUpdate(
287
        $id,
288
        $chat_id,
289
        $message_id,
290
        $inline_query_id,
291
        $chosen_inline_result_id,
292
        $callback_query_id,
293
        $edited_message_id
294
    ) {
295
        if ($message_id === null && $inline_query_id === null && $chosen_inline_result_id === null && $callback_query_id === null && $edited_message_id === null) {
296
            throw new TelegramException('message_id, inline_query_id, chosen_inline_result_id, callback_query_id, edited_message_id are all null');
297
        }
298
299
        if (!self::isDbConnected()) {
300
            return false;
301
        }
302
303
        try {
304
            $sth = self::$pdo->prepare('
305
                INSERT IGNORE INTO `' . TB_TELEGRAM_UPDATE . '`
306
                (`id`, `chat_id`, `message_id`, `inline_query_id`, `chosen_inline_result_id`, `callback_query_id`, `edited_message_id`)
307
                VALUES
308
                (:id, :chat_id, :message_id, :inline_query_id, :chosen_inline_result_id, :callback_query_id, :edited_message_id)
309
            ');
310
311
            $sth->bindParam(':id', $id, PDO::PARAM_INT);
312
            $sth->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
313
            $sth->bindParam(':message_id', $message_id, PDO::PARAM_INT);
314
            $sth->bindParam(':inline_query_id', $inline_query_id, PDO::PARAM_INT);
315
            $sth->bindParam(':chosen_inline_result_id', $chosen_inline_result_id, PDO::PARAM_INT);
316
            $sth->bindParam(':callback_query_id', $callback_query_id, PDO::PARAM_INT);
317
            $sth->bindParam(':edited_message_id', $edited_message_id, PDO::PARAM_INT);
318
319
            return $sth->execute();
320
        } catch (PDOException $e) {
321
            throw new TelegramException($e->getMessage());
322
        }
323
    }
324
325
    /**
326
     * Insert users and save their connection to chats
327
     *
328
     * @param  \Longman\TelegramBot\Entities\User $user
329
     * @param  string                             $date
330
     * @param  \Longman\TelegramBot\Entities\Chat $chat
331
     *
332
     * @return bool If the insert was successful
333
     * @throws \Longman\TelegramBot\Exception\TelegramException
334
     */
335 6
    public static function insertUser(User $user, $date, Chat $chat = null)
336
    {
337 6
        if (!self::isDbConnected()) {
338
            return false;
339
        }
340
341 6
        $user_id    = $user->getId();
342 6
        $username   = $user->getUsername();
343 6
        $first_name = $user->getFirstName();
344 6
        $last_name  = $user->getLastName();
345
346
        try {
347 6
            $sth = self::$pdo->prepare('
348 6
                INSERT INTO `' . TB_USER . '`
349
                (`id`, `username`, `first_name`, `last_name`, `created_at`, `updated_at`)
350
                VALUES
351
                (:id, :username, :first_name, :last_name, :date, :date)
352
                ON DUPLICATE KEY UPDATE
353
                    `username`   = :username,
354
                    `first_name` = :first_name,
355
                    `last_name`  = :last_name,
356
                    `updated_at` = :date
357 6
            ');
358
359 6
            $sth->bindParam(':id', $user_id, PDO::PARAM_INT);
360 6
            $sth->bindParam(':username', $username, PDO::PARAM_STR, 255);
361 6
            $sth->bindParam(':first_name', $first_name, PDO::PARAM_STR, 255);
362 6
            $sth->bindParam(':last_name', $last_name, PDO::PARAM_STR, 255);
363 6
            $sth->bindParam(':date', $date, PDO::PARAM_STR);
364
365 6
            $status = $sth->execute();
366
        } catch (PDOException $e) {
367
            throw new TelegramException($e->getMessage());
368
        }
369
370
        //insert also the relationship to the chat into user_chat table
371 6
        if ($chat instanceof Chat) {
372 6
            $chat_id = $chat->getId();
373
            try {
374 6
                $sth = self::$pdo->prepare('
375 6
                    INSERT IGNORE INTO `' . TB_USER_CHAT . '`
376
                    (`user_id`, `chat_id`)
377
                    VALUES
378
                    (:user_id, :chat_id)
379 6
                ');
380
381 6
                $sth->bindParam(':user_id', $user_id, PDO::PARAM_INT);
382 6
                $sth->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
383
384 6
                $status = $sth->execute();
385
            } catch (PDOException $e) {
386
                throw new TelegramException($e->getMessage());
387
            }
388
        }
389
390 6
        return $status;
391
    }
392
393
    /**
394
     * Insert chat
395
     *
396
     * @param  \Longman\TelegramBot\Entities\Chat $chat
397
     * @param  string                             $date
398
     * @param  int                                $migrate_to_chat_id
399
     *
400
     * @return bool If the insert was successful
401
     * @throws \Longman\TelegramBot\Exception\TelegramException
402
     */
403 6
    public static function insertChat(Chat $chat, $date, $migrate_to_chat_id = null)
404
    {
405 6
        if (!self::isDbConnected()) {
406
            return false;
407
        }
408
409 6
        $chat_id    = $chat->getId();
410 6
        $chat_title = $chat->getTitle();
411 6
        $chat_type  = $chat->getType();
412
413
        try {
414 6
            $sth = self::$pdo->prepare('
415 6
                INSERT INTO `' . TB_CHAT . '`
416
                (`id`, `type`, `title`, `created_at` ,`updated_at`, `old_id`)
417
                VALUES
418
                (:id, :type, :title, :date, :date, :oldid)
419
                ON DUPLICATE KEY UPDATE
420
                    `type`       = :type,
421
                    `title`      = :title,
422
                    `updated_at` = :date
423 6
            ');
424
425 6
            if ($migrate_to_chat_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $migrate_to_chat_id of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
426
                $chat_type = 'supergroup';
427
428
                $sth->bindParam(':id', $migrate_to_chat_id, PDO::PARAM_INT);
429
                $sth->bindParam(':oldid', $chat_id, PDO::PARAM_INT);
430
            } else {
431 6
                $sth->bindParam(':id', $chat_id, PDO::PARAM_INT);
432 6
                $sth->bindParam(':oldid', $migrate_to_chat_id, PDO::PARAM_INT);
433
            }
434
435 6
            $sth->bindParam(':type', $chat_type, PDO::PARAM_INT);
436 6
            $sth->bindParam(':title', $chat_title, PDO::PARAM_STR, 255);
437 6
            $sth->bindParam(':date', $date, PDO::PARAM_STR);
438
439 6
            return $sth->execute();
440
        } catch (PDOException $e) {
441
            throw new TelegramException($e->getMessage());
442
        }
443
    }
444
445
    /**
446
     * Insert request into database
447
     *
448
     * @todo self::$pdo->lastInsertId() - unsafe usage if expected previous insert fails?
449
     *
450
     * @param \Longman\TelegramBot\Entities\Update $update
451
     *
452
     * @return bool
453
     * @throws \Longman\TelegramBot\Exception\TelegramException
454
     */
455
    public static function insertRequest(Update $update)
456
    {
457
        $update_id   = $update->getUpdateId();
458
        $update_type = $update->getUpdateType();
459
460
        if ($update_type === 'message') {
461
            $message = $update->getMessage();
462
463
            if (self::insertMessageRequest($message)) {
464
                $message_id = $message->getMessageId();
465
                $chat_id    = $message->getChat()->getId();
466
467
                return self::insertTelegramUpdate($update_id, $chat_id, $message_id, null, null, null, null);
468
            }
469 View Code Duplication
        } elseif ($update_type === 'inline_query') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
470
            $inline_query = $update->getInlineQuery();
471
472
            if (self::insertInlineQueryRequest($inline_query)) {
473
                $inline_query_id = $inline_query->getId();
474
475
                return self::insertTelegramUpdate($update_id, null, null, $inline_query_id, null, null, null);
476
            }
477
        } elseif ($update_type === 'chosen_inline_result') {
478
            $chosen_inline_result = $update->getChosenInlineResult();
479
480
            if (self::insertChosenInlineResultRequest($chosen_inline_result)) {
481
                $chosen_inline_result_local_id = self::$pdo->lastInsertId();
482
483
                return self::insertTelegramUpdate(
484
                    $update_id,
485
                    null,
486
                    null,
487
                    null,
488
                    $chosen_inline_result_local_id,
489
                    null,
490
                    null
491
                );
492
            }
493 View Code Duplication
        } elseif ($update_type === 'callback_query') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
494
            $callback_query = $update->getCallbackQuery();
495
496
            if (self::insertCallbackQueryRequest($callback_query)) {
497
                $callback_query_id = $callback_query->getId();
498
499
                return self::insertTelegramUpdate($update_id, null, null, null, null, $callback_query_id, null);
500
            }
501
        } elseif ($update_type === 'edited_message') {
502
            $edited_message = $update->getEditedMessage();
503
504
            if (self::insertEditedMessageRequest($edited_message)) {
505
                $chat_id                 = $edited_message->getChat()->getId();
506
                $edited_message_local_id = self::$pdo->lastInsertId();
507
508
                return self::insertTelegramUpdate(
509
                    $update_id,
510
                    $chat_id,
511
                    null,
512
                    null,
513
                    null,
514
                    null,
515
                    $edited_message_local_id
516
                );
517
            }
518
        }
519
520
        return false;
521
    }
522
523
    /**
524
     * Insert inline query request into database
525
     *
526
     * @param \Longman\TelegramBot\Entities\InlineQuery $inline_query
527
     *
528
     * @return bool If the insert was successful
529
     * @throws \Longman\TelegramBot\Exception\TelegramException
530
     */
531 View Code Duplication
    public static function insertInlineQueryRequest(InlineQuery $inline_query)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
532
    {
533
        if (!self::isDbConnected()) {
534
            return false;
535
        }
536
537
        try {
538
            $sth = self::$pdo->prepare('
539
                INSERT IGNORE INTO `' . TB_INLINE_QUERY . '`
540
                (`id`, `user_id`, `location`, `query`, `offset`, `created_at`)
541
                VALUES
542
                (:inline_query_id, :user_id, :location, :query, :param_offset, :created_at)
543
            ');
544
545
            $date            = self::getTimestamp();
546
            $inline_query_id = $inline_query->getId();
547
            $from            = $inline_query->getFrom();
548
            $user_id         = null;
549
            if ($from instanceof User) {
550
                $user_id = $from->getId();
551
                self::insertUser($from, $date);
552
            }
553
554
            $location = $inline_query->getLocation();
555
            $query    = $inline_query->getQuery();
556
            $offset   = $inline_query->getOffset();
557
558
            $sth->bindParam(':inline_query_id', $inline_query_id, PDO::PARAM_INT);
559
            $sth->bindParam(':user_id', $user_id, PDO::PARAM_INT);
560
            $sth->bindParam(':location', $location, PDO::PARAM_STR);
561
            $sth->bindParam(':query', $query, PDO::PARAM_STR);
562
            $sth->bindParam(':param_offset', $offset, PDO::PARAM_STR);
563
            $sth->bindParam(':created_at', $date, PDO::PARAM_STR);
564
565
            return $sth->execute();
566
        } catch (PDOException $e) {
567
            throw new TelegramException($e->getMessage());
568
        }
569
    }
570
571
    /**
572
     * Insert chosen inline result request into database
573
     *
574
     * @param \Longman\TelegramBot\Entities\ChosenInlineResult $chosen_inline_result
575
     *
576
     * @return bool If the insert was successful
577
     * @throws \Longman\TelegramBot\Exception\TelegramException
578
     */
579 View Code Duplication
    public static function insertChosenInlineResultRequest(ChosenInlineResult $chosen_inline_result)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
580
    {
581
        if (!self::isDbConnected()) {
582
            return false;
583
        }
584
585
        try {
586
            $sth = self::$pdo->prepare('
587
                INSERT INTO `' . TB_CHOSEN_INLINE_RESULT . '`
588
                (`result_id`, `user_id`, `location`, `inline_message_id`, `query`, `created_at`)
589
                VALUES
590
                (:result_id, :user_id, :location, :inline_message_id, :query, :created_at)
591
            ');
592
593
            $date      = self::getTimestamp();
594
            $result_id = $chosen_inline_result->getResultId();
595
            $from      = $chosen_inline_result->getFrom();
596
            $user_id   = null;
597
            if ($from instanceof User) {
598
                $user_id = $from->getId();
599
                self::insertUser($from, $date);
600
            }
601
602
            $location          = $chosen_inline_result->getLocation();
603
            $inline_message_id = $chosen_inline_result->getInlineMessageId();
604
            $query             = $chosen_inline_result->getQuery();
605
606
            $sth->bindParam(':result_id', $result_id, PDO::PARAM_STR);
607
            $sth->bindParam(':user_id', $user_id, PDO::PARAM_INT);
608
            $sth->bindParam(':location', $location, PDO::PARAM_INT);
609
            $sth->bindParam(':inline_message_id', $inline_message_id, PDO::PARAM_STR);
610
            $sth->bindParam(':query', $query, PDO::PARAM_STR);
611
            $sth->bindParam(':created_at', $date, PDO::PARAM_STR);
612
613
            return $sth->execute();
614
        } catch (PDOException $e) {
615
            throw new TelegramException($e->getMessage());
616
        }
617
    }
618
619
    /**
620
     * Insert callback query request into database
621
     *
622
     * @param \Longman\TelegramBot\Entities\CallbackQuery $callback_query
623
     *
624
     * @return bool If the insert was successful
625
     * @throws \Longman\TelegramBot\Exception\TelegramException
626
     */
627
    public static function insertCallbackQueryRequest(CallbackQuery $callback_query)
628
    {
629
        if (!self::isDbConnected()) {
630
            return false;
631
        }
632
633
        try {
634
            $sth = self::$pdo->prepare('
635
                INSERT IGNORE INTO `' . TB_CALLBACK_QUERY . '`
636
                (`id`, `user_id`, `chat_id`, `message_id`, `inline_message_id`, `data`, `created_at`)
637
                VALUES
638
                (:callback_query_id, :user_id, :chat_id, :message_id, :inline_message_id, :data, :created_at)
639
            ');
640
641
            $date              = self::getTimestamp();
642
            $callback_query_id = $callback_query->getId();
643
            $from              = $callback_query->getFrom();
644
            $user_id           = null;
645
            if ($from instanceof User) {
646
                $user_id = $from->getId();
647
                self::insertUser($from, $date);
648
            }
649
650
            $message    = $callback_query->getMessage();
651
            $chat_id    = null;
652
            $message_id = null;
653
            if ($message instanceof Message) {
654
                $chat_id    = $message->getChat()->getId();
655
                $message_id = $message->getMessageId();
656
657
                $is_message = self::$pdo->query('
658
                    SELECT *
659
                    FROM `' . TB_MESSAGE . '`
660
                    WHERE `id` = ' . $message_id . '
661
                      AND `chat_id` = ' . $chat_id . '
662
                    LIMIT 1
663
                ')->rowCount();
664
665
                if ($is_message) {
666
                    self::insertEditedMessageRequest($message);
667
                } else {
668
                    self::insertMessageRequest($message);
669
                }
670
            }
671
672
            $inline_message_id = $callback_query->getInlineMessageId();
673
            $data              = $callback_query->getData();
674
675
            $sth->bindParam(':callback_query_id', $callback_query_id, PDO::PARAM_INT);
676
            $sth->bindParam(':user_id', $user_id, PDO::PARAM_INT);
677
            $sth->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
678
            $sth->bindParam(':message_id', $message_id, PDO::PARAM_INT);
679
            $sth->bindParam(':inline_message_id', $inline_message_id, PDO::PARAM_STR);
680
            $sth->bindParam(':data', $data, PDO::PARAM_STR);
681
            $sth->bindParam(':created_at', $date, PDO::PARAM_STR);
682
683
            return $sth->execute();
684
        } catch (PDOException $e) {
685
            throw new TelegramException($e->getMessage());
686
        }
687
    }
688
689
    /**
690
     * Insert Message request in db
691
     *
692
     * @param \Longman\TelegramBot\Entities\Message $message
693
     *
694
     * @return bool If the insert was successful
695
     * @throws \Longman\TelegramBot\Exception\TelegramException
696
     */
697 6
    public static function insertMessageRequest(Message $message)
698
    {
699 6
        if (!self::isDbConnected()) {
700
            return false;
701
        }
702
703 6
        $from = $message->getFrom();
704 6
        $chat = $message->getChat();
705
706 6
        $chat_id = $chat->getId();
707
708 6
        $date = self::getTimestamp($message->getDate());
709
710 6
        $forward_from       = $message->getForwardFrom();
711 6
        $forward_from_chat  = $message->getForwardFromChat();
712 6
        $photo              = self::entitiesArrayToJson($message->getPhoto(), '');
713 6
        $entities           = self::entitiesArrayToJson($message->getEntities(), null);
714 6
        $new_chat_member    = $message->getNewChatMember();
715 6
        $new_chat_photo     = self::entitiesArrayToJson($message->getNewChatPhoto(), '');
716 6
        $left_chat_member   = $message->getLeftChatMember();
717 6
        $migrate_to_chat_id = $message->getMigrateToChatId();
718
719
        //Insert chat, update chat id in case it migrated
720 6
        self::insertChat($chat, $date, $migrate_to_chat_id);
721
722
        //Insert user and the relation with the chat
723 6
        self::insertUser($from, $date, $chat);
724
725
        //Insert the forwarded message user in users table
726 6
        if ($forward_from instanceof User) {
727
            $forward_date = self::getTimestamp($message->getForwardDate());
728
            self::insertUser($forward_from, $forward_date);
729
            $forward_from = $forward_from->getId();
730
        }
731
732 6
        if ($forward_from_chat instanceof Chat) {
733
            $forward_date = self::getTimestamp($message->getForwardDate());
734
            self::insertChat($forward_from_chat, $forward_date);
735
            $forward_from_chat = $forward_from_chat->getId();
736
        }
737
738
        //New and left chat member
739 6
        if ($new_chat_member instanceof User) {
740
            //Insert the new chat user
741
            self::insertUser($new_chat_member, $date, $chat);
742
            $new_chat_member = $new_chat_member->getId();
743
        } elseif ($left_chat_member instanceof User) {
744
            //Insert the left chat user
745
            self::insertUser($left_chat_member, $date, $chat);
746
            $left_chat_member = $left_chat_member->getId();
747
        }
748
749
        try {
750 6
            $sth = self::$pdo->prepare('
751 6
                INSERT IGNORE INTO `' . TB_MESSAGE . '`
752
                (
753
                    `id`, `user_id`, `chat_id`, `date`, `forward_from`, `forward_from_chat`,
754
                    `forward_date`, `reply_to_chat`, `reply_to_message`, `text`, `entities`, `audio`, `document`,
755
                    `photo`, `sticker`, `video`, `voice`, `caption`, `contact`,
756
                    `location`, `venue`, `new_chat_member`, `left_chat_member`,
757
                    `new_chat_title`,`new_chat_photo`, `delete_chat_photo`, `group_chat_created`,
758
                    `supergroup_chat_created`, `channel_chat_created`,
759
                    `migrate_from_chat_id`, `migrate_to_chat_id`, `pinned_message`
760
                ) VALUES (
761
                    :message_id, :user_id, :chat_id, :date, :forward_from, :forward_from_chat,
762
                    :forward_date, :reply_to_chat, :reply_to_message, :text, :entities, :audio, :document,
763
                    :photo, :sticker, :video, :voice, :caption, :contact,
764
                    :location, :venue, :new_chat_member, :left_chat_member,
765
                    :new_chat_title, :new_chat_photo, :delete_chat_photo, :group_chat_created,
766
                    :supergroup_chat_created, :channel_chat_created,
767
                    :migrate_from_chat_id, :migrate_to_chat_id, :pinned_message
768
                )
769 6
            ');
770
771 6
            $message_id = $message->getMessageId();
772 6
            $from_id    = $from->getId();
773
774 6
            $reply_to_message    = $message->getReplyToMessage();
775 6
            $reply_to_message_id = null;
776 6
            if ($reply_to_message instanceof ReplyToMessage) {
777
                $reply_to_message_id = $reply_to_message->getMessageId();
778
                // please notice that, as explained in the documentation, reply_to_message don't contain other
779
                // reply_to_message field so recursion deep is 1
780
                self::insertMessageRequest($reply_to_message);
781
            }
782
783 6
            $text                    = $message->getText();
784 6
            $audio                   = $message->getAudio();
785 6
            $document                = $message->getDocument();
786 6
            $sticker                 = $message->getSticker();
787 6
            $video                   = $message->getVideo();
788 6
            $voice                   = $message->getVoice();
789 6
            $caption                 = $message->getCaption();
790 6
            $contact                 = $message->getContact();
791 6
            $location                = $message->getLocation();
792 6
            $venue                   = $message->getVenue();
793 6
            $new_chat_title          = $message->getNewChatTitle();
794 6
            $delete_chat_photo       = $message->getDeleteChatPhoto();
795 6
            $group_chat_created      = $message->getGroupChatCreated();
796 6
            $supergroup_chat_created = $message->getSupergroupChatCreated();
797 6
            $channel_chat_created    = $message->getChannelChatCreated();
798 6
            $migrate_from_chat_id    = $message->getMigrateFromChatId();
799 6
            $migrate_to_chat_id      = $message->getMigrateToChatId();
800 6
            $pinned_message          = $message->getPinnedMessage();
801
802 6
            $sth->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
803 6
            $sth->bindParam(':message_id', $message_id, PDO::PARAM_INT);
804 6
            $sth->bindParam(':user_id', $from_id, PDO::PARAM_INT);
805 6
            $sth->bindParam(':date', $date, PDO::PARAM_STR);
806 6
            $sth->bindParam(':forward_from', $forward_from, PDO::PARAM_INT);
807 6
            $sth->bindParam(':forward_from_chat', $forward_from_chat, PDO::PARAM_INT);
808 6
            $sth->bindParam(':forward_date', $forward_date, PDO::PARAM_STR);
809
810 6
            $reply_to_chat_id = null;
811 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...
812
                $reply_to_chat_id = $chat_id;
813
            }
814
815 6
            $sth->bindParam(':reply_to_chat', $reply_to_chat_id, PDO::PARAM_INT);
816 6
            $sth->bindParam(':reply_to_message', $reply_to_message_id, PDO::PARAM_INT);
817 6
            $sth->bindParam(':text', $text, PDO::PARAM_STR);
818 6
            $sth->bindParam(':entities', $entities, PDO::PARAM_STR);
819 6
            $sth->bindParam(':audio', $audio, PDO::PARAM_STR);
820 6
            $sth->bindParam(':document', $document, PDO::PARAM_STR);
821 6
            $sth->bindParam(':photo', $photo, PDO::PARAM_STR);
822 6
            $sth->bindParam(':sticker', $sticker, PDO::PARAM_STR);
823 6
            $sth->bindParam(':video', $video, PDO::PARAM_STR);
824 6
            $sth->bindParam(':voice', $voice, PDO::PARAM_STR);
825 6
            $sth->bindParam(':caption', $caption, PDO::PARAM_STR);
826 6
            $sth->bindParam(':contact', $contact, PDO::PARAM_STR);
827 6
            $sth->bindParam(':location', $location, PDO::PARAM_STR);
828 6
            $sth->bindParam(':venue', $venue, PDO::PARAM_STR);
829 6
            $sth->bindParam(':new_chat_member', $new_chat_member, PDO::PARAM_INT);
830 6
            $sth->bindParam(':left_chat_member', $left_chat_member, PDO::PARAM_INT);
831 6
            $sth->bindParam(':new_chat_title', $new_chat_title, PDO::PARAM_STR);
832 6
            $sth->bindParam(':new_chat_photo', $new_chat_photo, PDO::PARAM_STR);
833 6
            $sth->bindParam(':delete_chat_photo', $delete_chat_photo, PDO::PARAM_STR);
834 6
            $sth->bindParam(':group_chat_created', $group_chat_created, PDO::PARAM_STR);
835 6
            $sth->bindParam(':supergroup_chat_created', $supergroup_chat_created, PDO::PARAM_INT);
836 6
            $sth->bindParam(':channel_chat_created', $channel_chat_created, PDO::PARAM_INT);
837 6
            $sth->bindParam(':migrate_from_chat_id', $migrate_from_chat_id, PDO::PARAM_INT);
838 6
            $sth->bindParam(':migrate_to_chat_id', $migrate_to_chat_id, PDO::PARAM_INT);
839 6
            $sth->bindParam(':pinned_message', $pinned_message, PDO::PARAM_INT);
840
841 6
            return $sth->execute();
842
        } catch (PDOException $e) {
843
            throw new TelegramException($e->getMessage());
844
        }
845
    }
846
847
    /**
848
     * Insert Edited Message request in db
849
     *
850
     * @param \Longman\TelegramBot\Entities\Message $edited_message
851
     *
852
     * @return bool If the insert was successful
853
     * @throws \Longman\TelegramBot\Exception\TelegramException
854
     */
855
    public static function insertEditedMessageRequest(Message $edited_message)
856
    {
857
        if (!self::isDbConnected()) {
858
            return false;
859
        }
860
861
        $from = $edited_message->getFrom();
862
        $chat = $edited_message->getChat();
863
864
        $chat_id = $chat->getId();
865
866
        $edit_date = self::getTimestamp($edited_message->getEditDate());
867
868
        $entities = self::entitiesArrayToJson($edited_message->getEntities(), null);
869
870
        //Insert chat
871
        self::insertChat($chat, $edit_date);
872
873
        //Insert user and the relation with the chat
874
        self::insertUser($from, $edit_date, $chat);
875
876
        try {
877
            $sth = self::$pdo->prepare('
878
                INSERT IGNORE INTO `' . TB_EDITED_MESSAGE . '`
879
                (`chat_id`, `message_id`, `user_id`, `edit_date`, `text`, `entities`, `caption`)
880
                VALUES
881
                (:chat_id, :message_id, :user_id, :date, :text, :entities, :caption)
882
            ');
883
884
            $message_id = $edited_message->getMessageId();
885
            $from_id    = $from->getId();
886
887
            $text    = $edited_message->getText();
888
            $caption = $edited_message->getCaption();
889
890
            $sth->bindParam(':chat_id', $chat_id, PDO::PARAM_INT);
891
            $sth->bindParam(':message_id', $message_id, PDO::PARAM_INT);
892
            $sth->bindParam(':user_id', $from_id, PDO::PARAM_INT);
893
            $sth->bindParam(':date', $edit_date, PDO::PARAM_STR);
894
            $sth->bindParam(':text', $text, PDO::PARAM_STR);
895
            $sth->bindParam(':entities', $entities, PDO::PARAM_STR);
896
            $sth->bindParam(':caption', $caption, PDO::PARAM_STR);
897
898
            return $sth->execute();
899
        } catch (PDOException $e) {
900
            throw new TelegramException($e->getMessage());
901
        }
902
    }
903
904
    /**
905
     * Select Group and/or single Chats
906
     *
907
     * @param bool   $select_groups
908
     * @param bool   $select_super_groups
909
     * @param bool   $select_users
910
     * @param string $date_from
911
     * @param string $date_to
912
     * @param int    $chat_id
913
     * @param string $text
914
     *
915
     * @return array|bool (Selected chats or false if invalid arguments)
916
     * @throws \Longman\TelegramBot\Exception\TelegramException
917
     */
918
    public static function selectChats(
919
        $select_groups = true,
920
        $select_super_groups = true,
921
        $select_users = true,
922
        $date_from = null,
923
        $date_to = null,
924
        $chat_id = null,
925
        $text = null
926
    ) {
927
        if (!self::isDbConnected()) {
928
            return false;
929
        }
930
931
        if (!$select_groups && !$select_users && !$select_super_groups) {
932
            return false;
933
        }
934
935
        try {
936
            $query = '
937
                SELECT * ,
938
                ' . TB_CHAT . '.`id` AS `chat_id`,
939
                ' . TB_CHAT . '.`created_at` AS `chat_created_at`,
940
                ' . TB_CHAT . '.`updated_at` AS `chat_updated_at`
941
            ';
942
            if ($select_users) {
943
                $query .= '
944
                    , ' . TB_USER . '.`id` AS `user_id`
945
                    FROM `' . TB_CHAT . '`
946
                    LEFT JOIN `' . TB_USER . '`
947
                    ON ' . TB_CHAT . '.`id`=' . TB_USER . '.`id`
948
                ';
949
            } else {
950
                $query .= 'FROM `' . TB_CHAT . '`';
951
            }
952
953
            //Building parts of query
954
            $where  = [];
955
            $tokens = [];
956
957
            if (!$select_groups || !$select_users || !$select_super_groups) {
958
                $chat_or_user = [];
959
960
                $select_groups && $chat_or_user[] = TB_CHAT . '.`type` = "group"';
961
                $select_super_groups && $chat_or_user[] = TB_CHAT . '.`type` = "supergroup"';
962
                $select_users && $chat_or_user[] = TB_CHAT . '.`type` = "private"';
963
964
                $where[] = '(' . implode(' OR ', $chat_or_user) . ')';
965
            }
966
967
            if (null !== $date_from) {
968
                $where[]              = TB_CHAT . '.`updated_at` >= :date_from';
969
                $tokens[':date_from'] = $date_from;
970
            }
971
972
            if (null !== $date_to) {
973
                $where[]            = TB_CHAT . '.`updated_at` <= :date_to';
974
                $tokens[':date_to'] = $date_to;
975
            }
976
977
            if (null !== $chat_id) {
978
                $where[]            = TB_CHAT . '.`id` = :chat_id';
979
                $tokens[':chat_id'] = $chat_id;
980
            }
981
982
            if (null !== $text) {
983
                if ($select_users) {
984
                    $where[] = '(
985
                        LOWER(' . TB_CHAT . '.`title`) LIKE :text
986
                        OR LOWER(' . TB_USER . '.`first_name`) LIKE :text
987
                        OR LOWER(' . TB_USER . '.`last_name`) LIKE :text
988
                        OR LOWER(' . TB_USER . '.`username`) LIKE :text
989
                    )';
990
                } else {
991
                    $where[] = 'LOWER(' . TB_CHAT . '.`title`) LIKE :text';
992
                }
993
                $tokens[':text'] = '%' . strtolower($text) . '%';
994
            }
995
996
            if (!empty($where)) {
997
                $query .= ' WHERE ' . implode(' AND ', $where);
998
            }
999
1000
            $query .= ' ORDER BY ' . TB_CHAT . '.`updated_at` ASC';
1001
1002
            $sth = self::$pdo->prepare($query);
1003
            $sth->execute($tokens);
1004
1005
            return $sth->fetchAll(PDO::FETCH_ASSOC);
1006
        } catch (PDOException $e) {
1007
            throw new TelegramException($e->getMessage());
1008
        }
1009
    }
1010
}
1011