Completed
Push — master ( 4b2edc...52afdb )
by Armando
03:26 queued 01:23
created

DB::getTimestamp()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

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