Completed
Pull Request — develop (#364)
by Armando
02:36
created

DB::isDbConnected()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
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 6
        $chat_all_members_are_administrators = $chat->getAllMembersAreAdministrators();
413
414
        try {
415 6
            $sth = self::$pdo->prepare('
416 6
                INSERT INTO `' . TB_CHAT . '`
417
                (`id`, `type`, `title`, `all_members_are_administrators`, `created_at` ,`updated_at`, `old_id`)
418
                VALUES
419
                (:id, :type, :title, :all_members_are_administrators, :date, :date, :oldid)
420
                ON DUPLICATE KEY UPDATE
421
                    `type`                           = :type,
422
                    `title`                          = :title,
423
                    `all_members_are_administrators` = :all_members_are_administrators,
424
                    `updated_at`                     = :date
425 6
            ');
426
427 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...
428
                $chat_type = 'supergroup';
429
430
                $sth->bindParam(':id', $migrate_to_chat_id, PDO::PARAM_INT);
431
                $sth->bindParam(':oldid', $chat_id, PDO::PARAM_INT);
432
            } else {
433 6
                $sth->bindParam(':id', $chat_id, PDO::PARAM_INT);
434 6
                $sth->bindParam(':oldid', $migrate_to_chat_id, PDO::PARAM_INT);
435
            }
436
437 6
            $sth->bindParam(':type', $chat_type, PDO::PARAM_INT);
438 6
            $sth->bindParam(':title', $chat_title, PDO::PARAM_STR, 255);
439 6
            $sth->bindParam(':all_members_are_administrators', $chat_all_members_are_administrators, PDO::PARAM_INT);
440 6
            $sth->bindParam(':date', $date, PDO::PARAM_STR);
441
442 6
            return $sth->execute();
443
        } catch (PDOException $e) {
444
            throw new TelegramException($e->getMessage());
445
        }
446
    }
447
448
    /**
449
     * Insert request into database
450
     *
451
     * @todo self::$pdo->lastInsertId() - unsafe usage if expected previous insert fails?
452
     *
453
     * @param \Longman\TelegramBot\Entities\Update $update
454
     *
455
     * @return bool
456
     * @throws \Longman\TelegramBot\Exception\TelegramException
457
     */
458
    public static function insertRequest(Update $update)
459
    {
460
        $update_id   = $update->getUpdateId();
461
        $update_type = $update->getUpdateType();
462
463
        if ($update_type === 'message') {
464
            $message = $update->getMessage();
465
466 View Code Duplication
            if (self::insertMessageRequest($message)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
467
                $message_id = $message->getMessageId();
468
                $chat_id    = $message->getChat()->getId();
469
470
                return self::insertTelegramUpdate($update_id, $chat_id, $message_id, null, null, null, null);
471
            }
472 View Code Duplication
        } elseif ($update_type === 'edited_message') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
473
            $edited_message = $update->getEditedMessage();
474
475
            if (self::insertEditedMessageRequest($edited_message)) {
476
                $chat_id                 = $edited_message->getChat()->getId();
477
                $edited_message_local_id = self::$pdo->lastInsertId();
478
479
                return self::insertTelegramUpdate(
480
                    $update_id,
481
                    $chat_id,
482
                    null,
483
                    null,
484
                    null,
485
                    null,
486
                    $edited_message_local_id
487
                );
488
            }
489
        } else if ($update_type === 'channel_post') {
490
            $channel_post = $update->getChannelPost();
491
492 View Code Duplication
            if (self::insertMessageRequest($channel_post)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
493
                $message_id = $channel_post->getMessageId();
494
                $chat_id    = $channel_post->getChat()->getId();
495
496
                return self::insertTelegramUpdate($update_id, $chat_id, $message_id, null, null, null, null);
497
            }
498 View Code Duplication
        } elseif ($update_type === 'edited_channel_post') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

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