Passed
Push — master ( 7ecda6...2093cf )
by Armando
04:22 queued 02:31
created

DB::insertUser()   B

Complexity

Conditions 6
Paths 18

Size

Total Lines 56
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 6.256

Importance

Changes 6
Bugs 0 Features 0
Metric Value
cc 6
eloc 27
c 6
b 0
f 0
nc 18
nop 3
dl 0
loc 56
ccs 21
cts 26
cp 0.8077
crap 6.256
rs 8.8657

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This file is part of the TelegramBot package.
5
 *
6
 * (c) Avtandil Kikabidze aka LONGMAN <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 * Written by Marco Boretto <[email protected]>
11
 */
12
13
namespace Longman\TelegramBot;
14
15
use Longman\TelegramBot\Entities\CallbackQuery;
16
use Longman\TelegramBot\Entities\Chat;
17
use Longman\TelegramBot\Entities\ChosenInlineResult;
18
use Longman\TelegramBot\Entities\InlineQuery;
19
use Longman\TelegramBot\Entities\Message;
20
use Longman\TelegramBot\Entities\Payments\PreCheckoutQuery;
21
use Longman\TelegramBot\Entities\Payments\ShippingQuery;
22
use Longman\TelegramBot\Entities\Poll;
23
use Longman\TelegramBot\Entities\PollAnswer;
24
use Longman\TelegramBot\Entities\Update;
25
use Longman\TelegramBot\Entities\User;
26
use Longman\TelegramBot\Exception\TelegramException;
27
use PDO;
28
use PDOException;
29
30
class DB
31
{
32
    /**
33
     * MySQL credentials
34
     *
35
     * @var array
36
     */
37
    protected static $mysql_credentials = [];
38
39
    /**
40
     * PDO object
41
     *
42
     * @var PDO
43
     */
44
    protected static $pdo;
45
46
    /**
47
     * Table prefix
48
     *
49
     * @var string
50
     */
51
    protected static $table_prefix;
52
53
    /**
54
     * Telegram class object
55
     *
56
     * @var Telegram
57
     */
58
    protected static $telegram;
59
60
    /**
61
     * Initialize
62
     *
63
     * @param array    $credentials  Database connection details
64
     * @param Telegram $telegram     Telegram object to connect with this object
65
     * @param string   $table_prefix Table prefix
66
     * @param string   $encoding     Database character encoding
67
     *
68
     * @return PDO PDO database object
69
     * @throws TelegramException
70
     */
71 9
    public static function initialize(
72
        array $credentials,
73
        Telegram $telegram,
74
        $table_prefix = '',
75
        $encoding = 'utf8mb4'
76
    ): PDO {
77 9
        if (empty($credentials)) {
78
            throw new TelegramException('MySQL credentials not provided!');
79
        }
80
81 9
        $dsn = 'mysql:host=' . $credentials['host'] . ';dbname=' . $credentials['database'];
82 9
        if (!empty($credentials['port'])) {
83 9
            $dsn .= ';port=' . $credentials['port'];
84
        }
85
86 9
        $options = [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . $encoding];
87
        try {
88 9
            $pdo = new PDO($dsn, $credentials['user'], $credentials['password'], $options);
89 9
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
90
        } catch (PDOException $e) {
91
            throw new TelegramException($e->getMessage());
92
        }
93
94 9
        self::$pdo               = $pdo;
95 9
        self::$telegram          = $telegram;
96 9
        self::$mysql_credentials = $credentials;
97 9
        self::$table_prefix      = $table_prefix;
98
99 9
        self::defineTables();
100
101 9
        return self::$pdo;
102
    }
103
104
    /**
105
     * External Initialize
106
     *
107
     * Let you use the class with an external already existing Pdo Mysql connection.
108
     *
109
     * @param PDO      $external_pdo_connection PDO database object
110
     * @param Telegram $telegram                Telegram object to connect with this object
111
     * @param string   $table_prefix            Table prefix
112
     *
113
     * @return PDO PDO database object
114
     * @throws TelegramException
115
     */
116
    public static function externalInitialize(
117
        PDO $external_pdo_connection,
118
        Telegram $telegram,
119
        string $table_prefix = ''
120
    ): PDO {
121
        if ($external_pdo_connection === null) {
122
            throw new TelegramException('MySQL external connection not provided!');
123
        }
124
125
        self::$pdo               = $external_pdo_connection;
126
        self::$telegram          = $telegram;
127
        self::$mysql_credentials = [];
128
        self::$table_prefix      = $table_prefix;
129
130
        self::defineTables();
131
132
        return self::$pdo;
133
    }
134
135
    /**
136
     * Define all the tables with the proper prefix
137
     */
138 9
    protected static function defineTables(): void
139
    {
140
        $tables = [
141 9
            'callback_query',
142
            'chat',
143
            'chosen_inline_result',
144
            'edited_message',
145
            'inline_query',
146
            'message',
147
            'pre_checkout_query',
148
            'poll',
149
            'poll_answer',
150
            'request_limiter',
151
            'shipping_query',
152
            'telegram_update',
153
            'user',
154
            'user_chat',
155
        ];
156 9
        foreach ($tables as $table) {
157 9
            $table_name = 'TB_' . strtoupper($table);
158 9
            if (!defined($table_name)) {
159 1
                define($table_name, self::$table_prefix . $table);
160
            }
161
        }
162 9
    }
163
164
    /**
165
     * Check if database connection has been created
166
     *
167
     * @return bool
168
     */
169 9
    public static function isDbConnected(): bool
170
    {
171 9
        return self::$pdo !== null;
172
    }
173
174
    /**
175
     * Get the PDO object of the connected database
176
     *
177
     * @return PDO|null
178
     */
179
    public static function getPdo(): ?PDO
180
    {
181
        return self::$pdo;
182
    }
183
184
    /**
185
     * Fetch update(s) from DB
186
     *
187
     * @param int    $limit Limit the number of updates to fetch
188
     * @param string $id    Check for unique update id
189
     *
190
     * @return array|bool Fetched data or false if not connected
191
     * @throws TelegramException
192
     */
193
    public static function selectTelegramUpdate(int $limit = 0, string $id = '')
194
    {
195
        if (!self::isDbConnected()) {
196
            return false;
197
        }
198
199
        try {
200
            $sql = '
201
                SELECT `id`
202
                FROM `' . TB_TELEGRAM_UPDATE . '`
203
            ';
204
205
            if ($id !== '') {
206
                $sql .= ' WHERE `id` = :id';
207
            } else {
208
                $sql .= ' ORDER BY `id` DESC';
209
            }
210
211
            if ($limit > 0) {
212
                $sql .= ' LIMIT :limit';
213
            }
214
215
            $sth = self::$pdo->prepare($sql);
216
217
            if ($limit > 0) {
218
                $sth->bindValue(':limit', $limit, PDO::PARAM_INT);
219
            }
220
            if ($id !== '') {
221
                $sth->bindValue(':id', $id);
222
            }
223
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
     * Fetch message(s) from DB
234
     *
235
     * @param int $limit Limit the number of messages to fetch
236
     *
237
     * @return array|bool Fetched data or false if not connected
238
     * @throws TelegramException
239
     */
240
    public static function selectMessages(int $limit = 0)
241
    {
242
        if (!self::isDbConnected()) {
243
            return false;
244
        }
245
246
        try {
247
            $sql = '
248
                SELECT *
249
                FROM `' . TB_MESSAGE . '`
250
                ORDER BY `id` DESC
251
            ';
252
253
            if ($limit > 0) {
254
                $sql .= ' LIMIT :limit';
255
            }
256
257
            $sth = self::$pdo->prepare($sql);
258
259
            if ($limit > 0) {
260
                $sth->bindValue(':limit', $limit, PDO::PARAM_INT);
261
            }
262
263
            $sth->execute();
264
265
            return $sth->fetchAll(PDO::FETCH_ASSOC);
266
        } catch (PDOException $e) {
267
            throw new TelegramException($e->getMessage());
268
        }
269
    }
270
271
    /**
272
     * Convert from unix timestamp to timestamp
273
     *
274
     * @param ?int $unixtime Unix timestamp (if empty, current timestamp is used)
275
     *
276
     * @return string
277
     */
278 7
    protected static function getTimestamp(?int $unixtime = null): string
279
    {
280 7
        return date('Y-m-d H:i:s', $unixtime ?? time());
281
    }
282
283
    /**
284
     * Convert array of Entity items to a JSON array
285
     *
286
     * @todo Find a better way, as json_* functions are very heavy
287
     *
288
     * @param array $entities
289
     * @param mixed $default
290
     *
291
     * @return mixed
292
     */
293 6
    public static function entitiesArrayToJson(array $entities, $default = null)
294
    {
295 6
        if (empty($entities)) {
296 6
            return $default;
297
        }
298
299
        // Convert each Entity item into an object based on its JSON reflection
300
        $json_entities = array_map(function ($entity) {
301
            return json_decode($entity, true);
302
        }, $entities);
303
304
        return json_encode($json_entities);
305
    }
306
307
    /**
308
     * Insert entry to telegram_update table
309
     *
310
     * @param int         $update_id
311
     * @param int|null    $chat_id
312
     * @param int|null    $message_id
313
     * @param int|null    $edited_message_id
314
     * @param int|null    $channel_post_id
315
     * @param int|null    $edited_channel_post_id
316
     * @param string|null $inline_query_id
317
     * @param string|null $chosen_inline_result_id
318
     * @param string|null $callback_query_id
319
     * @param string|null $shipping_query_id
320
     * @param string|null $pre_checkout_query_id
321
     * @param string|null $poll_id
322
     * @param string|null $poll_answer_poll_id
323
     *
324
     * @return bool If the insert was successful
325
     * @throws TelegramException
326
     */
327
    protected static function insertTelegramUpdate(
328
        int $update_id,
329
        ?int $chat_id = null,
330
        ?int $message_id = null,
331
        ?int $edited_message_id = null,
332
        ?int $channel_post_id = null,
333
        ?int $edited_channel_post_id = null,
334
        ?string $inline_query_id = null,
335
        ?string $chosen_inline_result_id = null,
336
        ?string $callback_query_id = null,
337
        ?string $shipping_query_id = null,
338
        ?string $pre_checkout_query_id = null,
339
        ?string $poll_id = null,
340
        ?string $poll_answer_poll_id = null
341
    ): ?bool {
342
        if ($message_id === null && $edited_message_id === null && $channel_post_id === null && $edited_channel_post_id === null && $inline_query_id === null && $chosen_inline_result_id === null && $callback_query_id === null && $shipping_query_id === null && $pre_checkout_query_id === null && $poll_id === null && $poll_answer_poll_id === null) {
343
            throw new TelegramException('message_id, edited_message_id, channel_post_id, edited_channel_post_id, inline_query_id, chosen_inline_result_id, callback_query_id, shipping_query_id, pre_checkout_query_id, poll_id, poll_answer_poll_id are all null');
344
        }
345
346
        if (!self::isDbConnected()) {
347
            return false;
348
        }
349
350
        try {
351
            $sth = self::$pdo->prepare('
352
                INSERT IGNORE INTO `' . TB_TELEGRAM_UPDATE . '`
353
                (`id`, `chat_id`, `message_id`, `edited_message_id`, `channel_post_id`, `edited_channel_post_id`, `inline_query_id`, `chosen_inline_result_id`, `callback_query_id`, `shipping_query_id`, `pre_checkout_query_id`, `poll_id`, `poll_answer_poll_id`)
354
                VALUES
355
                (:id, :chat_id, :message_id, :edited_message_id, :channel_post_id, :edited_channel_post_id, :inline_query_id, :chosen_inline_result_id, :callback_query_id, :shipping_query_id, :pre_checkout_query_id, :poll_id, :poll_answer_poll_id)
356
            ');
357
358
            $sth->bindValue(':id', $update_id);
359
            $sth->bindValue(':chat_id', $chat_id);
360
            $sth->bindValue(':message_id', $message_id);
361
            $sth->bindValue(':edited_message_id', $edited_message_id);
362
            $sth->bindValue(':channel_post_id', $channel_post_id);
363
            $sth->bindValue(':edited_channel_post_id', $edited_channel_post_id);
364
            $sth->bindValue(':inline_query_id', $inline_query_id);
365
            $sth->bindValue(':chosen_inline_result_id', $chosen_inline_result_id);
366
            $sth->bindValue(':callback_query_id', $callback_query_id);
367
            $sth->bindValue(':shipping_query_id', $shipping_query_id);
368
            $sth->bindValue(':pre_checkout_query_id', $pre_checkout_query_id);
369
            $sth->bindValue(':poll_id', $poll_id);
370
            $sth->bindValue(':poll_answer_poll_id', $poll_answer_poll_id);
371
372
            return $sth->execute();
373
        } catch (PDOException $e) {
374
            throw new TelegramException($e->getMessage());
375
        }
376
    }
377
378
    /**
379
     * Insert users and save their connection to chats
380
     *
381
     * @param User        $user
382
     * @param string|null $date
383
     * @param Chat|null   $chat
384
     *
385
     * @return bool If the insert was successful
386
     * @throws TelegramException
387
     */
388 6
    public static function insertUser(User $user, ?string $date = null, ?Chat $chat = null): bool
389
    {
390 6
        if (!self::isDbConnected()) {
391
            return false;
392
        }
393
394
        try {
395 6
            $sth = self::$pdo->prepare('
396 6
                INSERT INTO `' . TB_USER . '`
397
                (`id`, `is_bot`, `username`, `first_name`, `last_name`, `language_code`, `created_at`, `updated_at`)
398
                VALUES
399
                (:id, :is_bot, :username, :first_name, :last_name, :language_code, :created_at, :updated_at)
400
                ON DUPLICATE KEY UPDATE
401
                    `is_bot`         = VALUES(`is_bot`),
402
                    `username`       = VALUES(`username`),
403
                    `first_name`     = VALUES(`first_name`),
404
                    `last_name`      = VALUES(`last_name`),
405
                    `language_code`  = VALUES(`language_code`),
406
                    `updated_at`     = VALUES(`updated_at`)
407
            ');
408
409 6
            $sth->bindValue(':id', $user->getId());
410 6
            $sth->bindValue(':is_bot', $user->getIsBot(), PDO::PARAM_INT);
411 6
            $sth->bindValue(':username', $user->getUsername());
412 6
            $sth->bindValue(':first_name', $user->getFirstName());
413 6
            $sth->bindValue(':last_name', $user->getLastName());
414 6
            $sth->bindValue(':language_code', $user->getLanguageCode());
415 6
            $date = $date ?: self::getTimestamp();
416 6
            $sth->bindValue(':created_at', $date);
417 6
            $sth->bindValue(':updated_at', $date);
418
419 6
            $status = $sth->execute();
420
        } catch (PDOException $e) {
421
            throw new TelegramException($e->getMessage());
422
        }
423
424
        // Also insert the relationship to the chat into the user_chat table
425 6
        if ($chat) {
426
            try {
427 6
                $sth = self::$pdo->prepare('
428 6
                    INSERT IGNORE INTO `' . TB_USER_CHAT . '`
429
                    (`user_id`, `chat_id`)
430
                    VALUES
431
                    (:user_id, :chat_id)
432
                ');
433
434 6
                $sth->bindValue(':user_id', $user->getId());
435 6
                $sth->bindValue(':chat_id', $chat->getId());
436
437 6
                $status = $sth->execute();
438
            } catch (PDOException $e) {
439
                throw new TelegramException($e->getMessage());
440
            }
441
        }
442
443 6
        return $status;
444
    }
445
446
    /**
447
     * Insert chat
448
     *
449
     * @param Chat        $chat
450
     * @param string|null $date
451
     * @param int|null    $migrate_to_chat_id
452
     *
453
     * @return bool If the insert was successful
454
     * @throws TelegramException
455
     */
456 6
    public static function insertChat(Chat $chat, ?string $date = null, ?int $migrate_to_chat_id = null): ?bool
457
    {
458 6
        if (!self::isDbConnected()) {
459
            return false;
460
        }
461
462
        try {
463 6
            $sth = self::$pdo->prepare('
464 6
                INSERT IGNORE INTO `' . TB_CHAT . '`
465
                (`id`, `type`, `title`, `username`, `first_name`, `last_name`, `all_members_are_administrators`, `created_at` ,`updated_at`, `old_id`)
466
                VALUES
467
                (:id, :type, :title, :username, :first_name, :last_name, :all_members_are_administrators, :created_at, :updated_at, :old_id)
468
                ON DUPLICATE KEY UPDATE
469
                    `type`                           = VALUES(`type`),
470
                    `title`                          = VALUES(`title`),
471
                    `username`                       = VALUES(`username`),
472
                    `first_name`                     = VALUES(`first_name`),
473
                    `last_name`                      = VALUES(`last_name`),
474
                    `all_members_are_administrators` = VALUES(`all_members_are_administrators`),
475
                    `updated_at`                     = VALUES(`updated_at`)
476
            ');
477
478 6
            $chat_id   = $chat->getId();
479 6
            $chat_type = $chat->getType();
480
481 6
            if ($migrate_to_chat_id !== null) {
482
                $chat_type = 'supergroup';
483
484
                $sth->bindValue(':id', $migrate_to_chat_id);
485
                $sth->bindValue(':old_id', $chat_id);
486
            } else {
487 6
                $sth->bindValue(':id', $chat_id);
488 6
                $sth->bindValue(':old_id', $migrate_to_chat_id);
489
            }
490
491 6
            $sth->bindValue(':type', $chat_type);
492 6
            $sth->bindValue(':title', $chat->getTitle());
493 6
            $sth->bindValue(':username', $chat->getUsername());
494 6
            $sth->bindValue(':first_name', $chat->getFirstName());
495 6
            $sth->bindValue(':last_name', $chat->getLastName());
496 6
            $sth->bindValue(':all_members_are_administrators', $chat->getAllMembersAreAdministrators(), PDO::PARAM_INT);
0 ignored issues
show
Deprecated Code introduced by
The function Longman\TelegramBot\Enti...bersAreAdministrators() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

496
            $sth->bindValue(':all_members_are_administrators', /** @scrutinizer ignore-deprecated */ $chat->getAllMembersAreAdministrators(), PDO::PARAM_INT);
Loading history...
497 6
            $date = $date ?: self::getTimestamp();
498 6
            $sth->bindValue(':created_at', $date);
499 6
            $sth->bindValue(':updated_at', $date);
500
501 6
            return $sth->execute();
502
        } catch (PDOException $e) {
503
            throw new TelegramException($e->getMessage());
504
        }
505
    }
506
507
    /**
508
     * Insert request into database
509
     *
510
     * @todo self::$pdo->lastInsertId() - unsafe usage if expected previous insert fails?
511
     *
512
     * @param Update $update
513
     *
514
     * @return bool
515
     * @throws TelegramException
516
     */
517
    public static function insertRequest(Update $update): bool
518
    {
519
        if (!self::isDbConnected()) {
520
            return false;
521
        }
522
523
        $chat_id                 = null;
524
        $message_id              = null;
525
        $edited_message_id       = null;
526
        $channel_post_id         = null;
527
        $edited_channel_post_id  = null;
528
        $inline_query_id         = null;
529
        $chosen_inline_result_id = null;
530
        $callback_query_id       = null;
531
        $shipping_query_id       = null;
532
        $pre_checkout_query_id   = null;
533
        $poll_id                 = null;
534
        $poll_answer_poll_id     = null;
535
536
        if (($message = $update->getMessage()) && self::insertMessageRequest($message)) {
537
            $chat_id    = $message->getChat()->getId();
538
            $message_id = $message->getMessageId();
539
        } elseif (($edited_message = $update->getEditedMessage()) && self::insertEditedMessageRequest($edited_message)) {
540
            $chat_id           = $edited_message->getChat()->getId();
541
            $edited_message_id = (int) self::$pdo->lastInsertId();
542
        } elseif (($channel_post = $update->getChannelPost()) && self::insertMessageRequest($channel_post)) {
543
            $chat_id         = $channel_post->getChat()->getId();
544
            $channel_post_id = $channel_post->getMessageId();
545
        } elseif (($edited_channel_post = $update->getEditedChannelPost()) && self::insertEditedMessageRequest($edited_channel_post)) {
546
            $chat_id                = $edited_channel_post->getChat()->getId();
547
            $edited_channel_post_id = (int) self::$pdo->lastInsertId();
548
        } elseif (($inline_query = $update->getInlineQuery()) && self::insertInlineQueryRequest($inline_query)) {
549
            $inline_query_id = $inline_query->getId();
550
        } elseif (($chosen_inline_result = $update->getChosenInlineResult()) && self::insertChosenInlineResultRequest($chosen_inline_result)) {
551
            $chosen_inline_result_id = self::$pdo->lastInsertId();
552
        } elseif (($callback_query = $update->getCallbackQuery()) && self::insertCallbackQueryRequest($callback_query)) {
553
            $callback_query_id = $callback_query->getId();
554
        } elseif (($shipping_query = $update->getShippingQuery()) && self::insertShippingQueryRequest($shipping_query)) {
555
            $shipping_query_id = $shipping_query->getId();
556
        } elseif (($pre_checkout_query = $update->getPreCheckoutQuery()) && self::insertPreCheckoutQueryRequest($pre_checkout_query)) {
557
            $pre_checkout_query_id = $pre_checkout_query->getId();
558
        } elseif (($poll = $update->getPoll()) && self::insertPollRequest($poll)) {
559
            $poll_id = $poll->getId();
560
        } elseif (($poll_answer = $update->getPollAnswer()) && self::insertPollAnswerRequest($poll_answer)) {
561
            $poll_answer_poll_id = $poll_answer->getPollId();
562
        } else {
563
            return false;
564
        }
565
566
        return self::insertTelegramUpdate(
567
            $update->getUpdateId(),
568
            $chat_id,
569
            $message_id,
570
            $edited_message_id,
571
            $channel_post_id,
572
            $edited_channel_post_id,
573
            $inline_query_id,
574
            $chosen_inline_result_id,
575
            $callback_query_id,
576
            $shipping_query_id,
577
            $pre_checkout_query_id,
578
            $poll_id,
579
            $poll_answer_poll_id
580
        );
581
    }
582
583
    /**
584
     * Insert inline query request into database
585
     *
586
     * @param InlineQuery $inline_query
587
     *
588
     * @return bool If the insert was successful
589
     * @throws TelegramException
590
     */
591
    public static function insertInlineQueryRequest(InlineQuery $inline_query): bool
592
    {
593
        if (!self::isDbConnected()) {
594
            return false;
595
        }
596
597
        try {
598
            $sth = self::$pdo->prepare('
599
                INSERT IGNORE INTO `' . TB_INLINE_QUERY . '`
600
                (`id`, `user_id`, `location`, `query`, `offset`, `created_at`)
601
                VALUES
602
                (:id, :user_id, :location, :query, :offset, :created_at)
603
            ');
604
605
            $date    = self::getTimestamp();
606
            $user_id = null;
607
608
            if ($user = $inline_query->getFrom()) {
609
                $user_id = $user->getId();
610
                self::insertUser($user, $date);
611
            }
612
613
            $sth->bindValue(':id', $inline_query->getId());
614
            $sth->bindValue(':user_id', $user_id);
615
            $sth->bindValue(':location', $inline_query->getLocation());
616
            $sth->bindValue(':query', $inline_query->getQuery());
617
            $sth->bindValue(':offset', $inline_query->getOffset());
618
            $sth->bindValue(':created_at', $date);
619
620
            return $sth->execute();
621
        } catch (PDOException $e) {
622
            throw new TelegramException($e->getMessage());
623
        }
624
    }
625
626
    /**
627
     * Insert chosen inline result request into database
628
     *
629
     * @param ChosenInlineResult $chosen_inline_result
630
     *
631
     * @return bool If the insert was successful
632
     * @throws TelegramException
633
     */
634
    public static function insertChosenInlineResultRequest(ChosenInlineResult $chosen_inline_result): bool
635
    {
636
        if (!self::isDbConnected()) {
637
            return false;
638
        }
639
640
        try {
641
            $sth = self::$pdo->prepare('
642
                INSERT INTO `' . TB_CHOSEN_INLINE_RESULT . '`
643
                (`result_id`, `user_id`, `location`, `inline_message_id`, `query`, `created_at`)
644
                VALUES
645
                (:result_id, :user_id, :location, :inline_message_id, :query, :created_at)
646
            ');
647
648
            $date    = self::getTimestamp();
649
            $user_id = null;
650
651
            if ($user = $chosen_inline_result->getFrom()) {
652
                $user_id = $user->getId();
653
                self::insertUser($user, $date);
654
            }
655
656
            $sth->bindValue(':result_id', $chosen_inline_result->getResultId());
657
            $sth->bindValue(':user_id', $user_id);
658
            $sth->bindValue(':location', $chosen_inline_result->getLocation());
659
            $sth->bindValue(':inline_message_id', $chosen_inline_result->getInlineMessageId());
660
            $sth->bindValue(':query', $chosen_inline_result->getQuery());
661
            $sth->bindValue(':created_at', $date);
662
663
            return $sth->execute();
664
        } catch (PDOException $e) {
665
            throw new TelegramException($e->getMessage());
666
        }
667
    }
668
669
    /**
670
     * Insert callback query request into database
671
     *
672
     * @param CallbackQuery $callback_query
673
     *
674
     * @return bool If the insert was successful
675
     * @throws TelegramException
676
     */
677
    public static function insertCallbackQueryRequest(CallbackQuery $callback_query): bool
678
    {
679
        if (!self::isDbConnected()) {
680
            return false;
681
        }
682
683
        try {
684
            $sth = self::$pdo->prepare('
685
                INSERT IGNORE INTO `' . TB_CALLBACK_QUERY . '`
686
                (`id`, `user_id`, `chat_id`, `message_id`, `inline_message_id`, `chat_instance`, `data`, `game_short_name`, `created_at`)
687
                VALUES
688
                (:id, :user_id, :chat_id, :message_id, :inline_message_id, :chat_instance, :data, :game_short_name, :created_at)
689
            ');
690
691
            $date    = self::getTimestamp();
692
            $user_id = null;
693
694
            if ($user = $callback_query->getFrom()) {
695
                $user_id = $user->getId();
696
                self::insertUser($user, $date);
697
            }
698
699
            $chat_id    = null;
700
            $message_id = null;
701
            if ($message = $callback_query->getMessage()) {
702
                $chat_id    = $message->getChat()->getId();
703
                $message_id = $message->getMessageId();
704
705
                $is_message = self::$pdo->query('
706
                    SELECT *
707
                    FROM `' . TB_MESSAGE . '`
708
                    WHERE `id` = ' . $message_id . '
709
                      AND `chat_id` = ' . $chat_id . '
710
                    LIMIT 1
711
                ')->rowCount();
712
713
                if ($is_message) {
714
                    self::insertEditedMessageRequest($message);
715
                } else {
716
                    self::insertMessageRequest($message);
717
                }
718
            }
719
720
            $sth->bindValue(':id', $callback_query->getId());
721
            $sth->bindValue(':user_id', $user_id);
722
            $sth->bindValue(':chat_id', $chat_id);
723
            $sth->bindValue(':message_id', $message_id);
724
            $sth->bindValue(':inline_message_id', $callback_query->getInlineMessageId());
725
            $sth->bindValue(':chat_instance', $callback_query->getChatInstance());
726
            $sth->bindValue(':data', $callback_query->getData());
727
            $sth->bindValue(':game_short_name', $callback_query->getGameShortName());
728
            $sth->bindValue(':created_at', $date);
729
730
            return $sth->execute();
731
        } catch (PDOException $e) {
732
            throw new TelegramException($e->getMessage());
733
        }
734
    }
735
736
    /**
737
     * Insert shipping query request into database
738
     *
739
     * @param ShippingQuery $shipping_query
740
     *
741
     * @return bool If the insert was successful
742
     * @throws TelegramException
743
     */
744
    public static function insertShippingQueryRequest(ShippingQuery $shipping_query): bool
745
    {
746
        if (!self::isDbConnected()) {
747
            return false;
748
        }
749
750
        try {
751
            $sth = self::$pdo->prepare('
752
                INSERT IGNORE INTO `' . TB_SHIPPING_QUERY . '`
753
                (`id`, `user_id`, `invoice_payload`, `shipping_address`, `created_at`)
754
                VALUES
755
                (:id, :user_id, :invoice_payload, :shipping_address, :created_at)
756
            ');
757
758
            $date    = self::getTimestamp();
759
            $user_id = null;
760
761
            if ($user = $shipping_query->getFrom()) {
762
                $user_id = $user->getId();
763
                self::insertUser($user, $date);
764
            }
765
766
            $sth->bindValue(':id', $shipping_query->getId());
767
            $sth->bindValue(':user_id', $user_id);
768
            $sth->bindValue(':invoice_payload', $shipping_query->getInvoicePayload());
769
            $sth->bindValue(':shipping_address', $shipping_query->getShippingAddress());
770
            $sth->bindValue(':created_at', $date);
771
772
            return $sth->execute();
773
        } catch (PDOException $e) {
774
            throw new TelegramException($e->getMessage());
775
        }
776
    }
777
778
    /**
779
     * Insert pre checkout query request into database
780
     *
781
     * @param PreCheckoutQuery $pre_checkout_query
782
     *
783
     * @return bool If the insert was successful
784
     * @throws TelegramException
785
     */
786
    public static function insertPreCheckoutQueryRequest(PreCheckoutQuery $pre_checkout_query): bool
787
    {
788
        if (!self::isDbConnected()) {
789
            return false;
790
        }
791
792
        try {
793
            $sth = self::$pdo->prepare('
794
                INSERT IGNORE INTO `' . TB_PRE_CHECKOUT_QUERY . '`
795
                (`id`, `user_id`, `currency`, `total_amount`, `invoice_payload`, `shipping_option_id`, `order_info`, `created_at`)
796
                VALUES
797
                (:id, :user_id, :currency, :total_amount, :invoice_payload, :shipping_option_id, :order_info, :created_at)
798
            ');
799
800
            $date    = self::getTimestamp();
801
            $user_id = null;
802
803
            if ($user = $pre_checkout_query->getFrom()) {
804
                $user_id = $user->getId();
805
                self::insertUser($user, $date);
806
            }
807
808
            $sth->bindValue(':id', $pre_checkout_query->getId());
809
            $sth->bindValue(':user_id', $user_id);
810
            $sth->bindValue(':currency', $pre_checkout_query->getCurrency());
811
            $sth->bindValue(':total_amount', $pre_checkout_query->getTotalAmount());
812
            $sth->bindValue(':invoice_payload', $pre_checkout_query->getInvoicePayload());
813
            $sth->bindValue(':shipping_option_id', $pre_checkout_query->getShippingOptionId());
814
            $sth->bindValue(':order_info', $pre_checkout_query->getOrderInfo());
815
            $sth->bindValue(':created_at', $date);
816
817
            return $sth->execute();
818
        } catch (PDOException $e) {
819
            throw new TelegramException($e->getMessage());
820
        }
821
    }
822
823
    /**
824
     * Insert poll request into database
825
     *
826
     * @param Poll $poll
827
     *
828
     * @return bool If the insert was successful
829
     * @throws TelegramException
830
     */
831
    public static function insertPollRequest(Poll $poll): bool
832
    {
833
        if (!self::isDbConnected()) {
834
            return false;
835
        }
836
837
        try {
838
            $sth = self::$pdo->prepare('
839
                INSERT INTO `' . TB_POLL . '`
840
                (`id`, `question`, `options`, `total_voter_count`, `is_closed`, `is_anonymous`, `type`, `allows_multiple_answers`, `correct_option_id`, `explanation`, `explanation_entities`, `open_period`, `close_date`, `created_at`)
841
                VALUES
842
                (:id, :question, :options, :total_voter_count, :is_closed, :is_anonymous, :type, :allows_multiple_answers, :correct_option_id, :explanation, :explanation_entities, :open_period, :close_date, :created_at)
843
                ON DUPLICATE KEY UPDATE
844
                    `options`                 = VALUES(`options`),
845
                    `total_voter_count`       = VALUES(`total_voter_count`),
846
                    `is_closed`               = VALUES(`is_closed`),
847
                    `is_anonymous`            = VALUES(`is_anonymous`),
848
                    `type`                    = VALUES(`type`),
849
                    `allows_multiple_answers` = VALUES(`allows_multiple_answers`),
850
                    `correct_option_id`       = VALUES(`correct_option_id`),
851
                    `explanation`             = VALUES(`explanation`),
852
                    `explanation_entities`    = VALUES(`explanation_entities`),
853
                    `open_period`             = VALUES(`open_period`),
854
                    `close_date`              = VALUES(`close_date`)
855
            ');
856
857
            $sth->bindValue(':id', $poll->getId());
858
            $sth->bindValue(':question', $poll->getQuestion());
859
            $sth->bindValue(':options', self::entitiesArrayToJson($poll->getOptions() ?: []));
860
            $sth->bindValue(':total_voter_count', $poll->getTotalVoterCount());
861
            $sth->bindValue(':is_closed', $poll->getIsClosed(), PDO::PARAM_INT);
862
            $sth->bindValue(':is_anonymous', $poll->getIsAnonymous(), PDO::PARAM_INT);
863
            $sth->bindValue(':type', $poll->getType());
864
            $sth->bindValue(':allows_multiple_answers', $poll->getAllowsMultipleAnswers(), PDO::PARAM_INT);
865
            $sth->bindValue(':correct_option_id', $poll->getCorrectOptionId());
866
            $sth->bindValue(':explanation', $poll->getExplanation());
867
            $sth->bindValue(':explanation_entities', self::entitiesArrayToJson($poll->getExplanationEntities() ?: []));
868
            $sth->bindValue(':open_period', $poll->getOpenPeriod());
869
            $sth->bindValue(':close_date', self::getTimestamp($poll->getCloseDate()));
870
            $sth->bindValue(':created_at', self::getTimestamp());
871
872
            return $sth->execute();
873
        } catch (PDOException $e) {
874
            throw new TelegramException($e->getMessage());
875
        }
876
    }
877
878
    /**
879
     * Insert poll answer request into database
880
     *
881
     * @param PollAnswer $poll_answer
882
     *
883
     * @return bool If the insert was successful
884
     * @throws TelegramException
885
     */
886
    public static function insertPollAnswerRequest(PollAnswer $poll_answer): bool
887
    {
888
        if (!self::isDbConnected()) {
889
            return false;
890
        }
891
892
        try {
893
            $sth = self::$pdo->prepare('
894
                INSERT INTO `' . TB_POLL_ANSWER . '`
895
                (`poll_id`, `user_id`, `option_ids`, `created_at`)
896
                VALUES
897
                (:poll_id, :user_id, :option_ids, :created_at)
898
                ON DUPLICATE KEY UPDATE
899
                    `option_ids` = VALUES(`option_ids`)
900
            ');
901
902
            $date    = self::getTimestamp();
903
            $user_id = null;
904
905
            if ($user = $poll_answer->getUser()) {
906
                $user_id = $user->getId();
907
                self::insertUser($user, $date);
908
            }
909
910
            $sth->bindValue(':poll_id', $poll_answer->getPollId());
911
            $sth->bindValue(':user_id', $user_id);
912
            $sth->bindValue(':option_ids', json_encode($poll_answer->getOptionIds()));
913
            $sth->bindValue(':created_at', $date);
914
915
            return $sth->execute();
916
        } catch (PDOException $e) {
917
            throw new TelegramException($e->getMessage());
918
        }
919
    }
920
921
    /**
922
     * Insert Message request in db
923
     *
924
     * @param Message $message
925
     *
926
     * @return bool If the insert was successful
927
     * @throws TelegramException
928
     */
929 6
    public static function insertMessageRequest(Message $message): bool
930
    {
931 6
        if (!self::isDbConnected()) {
932
            return false;
933
        }
934
935 6
        $date = self::getTimestamp($message->getDate());
936
937
        // Insert chat, update chat id in case it migrated
938 6
        $chat = $message->getChat();
939 6
        self::insertChat($chat, $date, $message->getMigrateToChatId());
940
941 6
        $sender_chat_id = null;
942 6
        if ($sender_chat = $message->getSenderChat()) {
943
            self::insertChat($sender_chat);
944
            $sender_chat_id = $sender_chat->getId();
945
        }
946
947
        // Insert user and the relation with the chat
948 6
        if ($user = $message->getFrom()) {
949 6
            self::insertUser($user, $date, $chat);
950
        }
951
952
        // Insert the forwarded message user in users table
953 6
        $forward_date = $message->getForwardDate() ? self::getTimestamp($message->getForwardDate()) : null;
954
955 6
        if ($forward_from = $message->getForwardFrom()) {
956
            self::insertUser($forward_from);
957
            $forward_from = $forward_from->getId();
958
        }
959 6
        if ($forward_from_chat = $message->getForwardFromChat()) {
960
            self::insertChat($forward_from_chat);
961
            $forward_from_chat = $forward_from_chat->getId();
962
        }
963
964 6
        $via_bot_id = null;
965 6
        if ($via_bot = $message->getViaBot()) {
966
            self::insertUser($via_bot);
967
            $via_bot_id = $via_bot->getId();
968
        }
969
970
        // New and left chat member
971 6
        $new_chat_members_ids = null;
972 6
        $left_chat_member_id  = null;
973
974 6
        $new_chat_members = $message->getNewChatMembers();
0 ignored issues
show
Bug introduced by
The method getNewChatMembers() does not exist on Longman\TelegramBot\Entities\Message. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

974
        /** @scrutinizer ignore-call */ 
975
        $new_chat_members = $message->getNewChatMembers();
Loading history...
975 6
        $left_chat_member = $message->getLeftChatMember();
976 6
        if (!empty($new_chat_members)) {
977
            foreach ($new_chat_members as $new_chat_member) {
978
                if ($new_chat_member instanceof User) {
979
                    // Insert the new chat user
980
                    self::insertUser($new_chat_member, $date, $chat);
981
                    $new_chat_members_ids[] = $new_chat_member->getId();
982
                }
983
            }
984
            $new_chat_members_ids = implode(',', $new_chat_members_ids);
985 6
        } elseif ($left_chat_member) {
0 ignored issues
show
introduced by
$left_chat_member is of type Longman\TelegramBot\Entities\User, thus it always evaluated to true.
Loading history...
986
            // Insert the left chat user
987
            self::insertUser($left_chat_member, $date, $chat);
988
            $left_chat_member_id = $left_chat_member->getId();
989
        }
990
991
        try {
992 6
            $sth = self::$pdo->prepare('
993 6
                INSERT IGNORE INTO `' . TB_MESSAGE . '`
994
                (
995
                    `id`, `user_id`, `chat_id`, `sender_chat_id`, `date`, `forward_from`, `forward_from_chat`, `forward_from_message_id`,
996
                    `forward_signature`, `forward_sender_name`, `forward_date`,
997
                    `reply_to_chat`, `reply_to_message`, `via_bot`, `edit_date`, `media_group_id`, `author_signature`, `text`, `entities`, `caption_entities`,
998
                    `audio`, `document`, `animation`, `game`, `photo`, `sticker`, `video`, `voice`, `video_note`, `caption`, `contact`,
999
                    `location`, `venue`, `poll`, `dice`, `new_chat_members`, `left_chat_member`,
1000
                    `new_chat_title`, `new_chat_photo`, `delete_chat_photo`, `group_chat_created`,
1001
                    `supergroup_chat_created`, `channel_chat_created`, `migrate_to_chat_id`, `migrate_from_chat_id`,
1002
                    `pinned_message`, `invoice`, `successful_payment`, `connected_website`, `passport_data`, `proximity_alert_triggered`, `reply_markup`
1003
                ) VALUES (
1004
                    :message_id, :user_id, :chat_id, :sender_chat_id, :date, :forward_from, :forward_from_chat, :forward_from_message_id,
1005
                    :forward_signature, :forward_sender_name, :forward_date,
1006
                    :reply_to_chat, :reply_to_message, :via_bot, :edit_date, :media_group_id, :author_signature, :text, :entities, :caption_entities,
1007
                    :audio, :document, :animation, :game, :photo, :sticker, :video, :voice, :video_note, :caption, :contact,
1008
                    :location, :venue, :poll, :dice, :new_chat_members, :left_chat_member,
1009
                    :new_chat_title, :new_chat_photo, :delete_chat_photo, :group_chat_created,
1010
                    :supergroup_chat_created, :channel_chat_created, :migrate_to_chat_id, :migrate_from_chat_id,
1011
                    :pinned_message, :invoice, :successful_payment, :connected_website, :passport_data, :proximity_alert_triggered, :reply_markup
1012
                )
1013
            ');
1014
1015 6
            $user_id = $user ? $user->getId() : null;
0 ignored issues
show
introduced by
$user is of type Longman\TelegramBot\Entities\User, thus it always evaluated to true.
Loading history...
1016 6
            $chat_id = $chat->getId();
1017
1018 6
            $reply_to_message_id = null;
1019 6
            if ($reply_to_message = $message->getReplyToMessage()) {
1020
                $reply_to_message_id = $reply_to_message->getMessageId();
1021
                // please notice that, as explained in the documentation, reply_to_message don't contain other
1022
                // reply_to_message field so recursion deep is 1
1023
                self::insertMessageRequest($reply_to_message);
1024
            }
1025
1026 6
            $sth->bindValue(':message_id', $message->getMessageId());
1027 6
            $sth->bindValue(':chat_id', $chat_id);
1028 6
            $sth->bindValue(':sender_chat_id', $sender_chat_id);
1029 6
            $sth->bindValue(':user_id', $user_id);
1030 6
            $sth->bindValue(':date', $date);
1031 6
            $sth->bindValue(':forward_from', $forward_from);
1032 6
            $sth->bindValue(':forward_from_chat', $forward_from_chat);
1033 6
            $sth->bindValue(':forward_from_message_id', $message->getForwardFromMessageId());
1034 6
            $sth->bindValue(':forward_signature', $message->getForwardSignature());
1035 6
            $sth->bindValue(':forward_sender_name', $message->getForwardSenderName());
1036 6
            $sth->bindValue(':forward_date', $forward_date);
1037
1038 6
            $reply_to_chat_id = null;
1039 6
            if ($reply_to_message_id !== null) {
1040
                $reply_to_chat_id = $chat_id;
1041
            }
1042 6
            $sth->bindValue(':reply_to_chat', $reply_to_chat_id);
1043 6
            $sth->bindValue(':reply_to_message', $reply_to_message_id);
1044
1045 6
            $sth->bindValue(':via_bot', $via_bot_id);
1046 6
            $sth->bindValue(':edit_date', $message->getEditDate());
1047 6
            $sth->bindValue(':media_group_id', $message->getMediaGroupId());
1048 6
            $sth->bindValue(':author_signature', $message->getAuthorSignature());
1049 6
            $sth->bindValue(':text', $message->getText());
1050 6
            $sth->bindValue(':entities', self::entitiesArrayToJson($message->getEntities() ?: []));
1051 6
            $sth->bindValue(':caption_entities', self::entitiesArrayToJson($message->getCaptionEntities() ?: []));
1052 6
            $sth->bindValue(':audio', $message->getAudio());
1053 6
            $sth->bindValue(':document', $message->getDocument());
1054 6
            $sth->bindValue(':animation', $message->getAnimation());
1055 6
            $sth->bindValue(':game', $message->getGame());
1056 6
            $sth->bindValue(':photo', self::entitiesArrayToJson($message->getPhoto() ?: []));
1057 6
            $sth->bindValue(':sticker', $message->getSticker());
1058 6
            $sth->bindValue(':video', $message->getVideo());
1059 6
            $sth->bindValue(':voice', $message->getVoice());
1060 6
            $sth->bindValue(':video_note', $message->getVideoNote());
1061 6
            $sth->bindValue(':caption', $message->getCaption());
1062 6
            $sth->bindValue(':contact', $message->getContact());
1063 6
            $sth->bindValue(':location', $message->getLocation());
1064 6
            $sth->bindValue(':venue', $message->getVenue());
1065 6
            $sth->bindValue(':poll', $message->getPoll());
1066 6
            $sth->bindValue(':dice', $message->getDice());
1067 6
            $sth->bindValue(':new_chat_members', $new_chat_members_ids);
1068 6
            $sth->bindValue(':left_chat_member', $left_chat_member_id);
1069 6
            $sth->bindValue(':new_chat_title', $message->getNewChatTitle());
1070 6
            $sth->bindValue(':new_chat_photo', self::entitiesArrayToJson($message->getNewChatPhoto() ?: []));
1071 6
            $sth->bindValue(':delete_chat_photo', $message->getDeleteChatPhoto());
1072 6
            $sth->bindValue(':group_chat_created', $message->getGroupChatCreated());
1073 6
            $sth->bindValue(':supergroup_chat_created', $message->getSupergroupChatCreated());
1074 6
            $sth->bindValue(':channel_chat_created', $message->getChannelChatCreated());
1075 6
            $sth->bindValue(':migrate_to_chat_id', $message->getMigrateToChatId());
1076 6
            $sth->bindValue(':migrate_from_chat_id', $message->getMigrateFromChatId());
1077 6
            $sth->bindValue(':pinned_message', $message->getPinnedMessage());
1078 6
            $sth->bindValue(':invoice', $message->getInvoice());
1079 6
            $sth->bindValue(':successful_payment', $message->getSuccessfulPayment());
1080 6
            $sth->bindValue(':connected_website', $message->getConnectedWebsite());
1081 6
            $sth->bindValue(':passport_data', $message->getPassportData());
1082 6
            $sth->bindValue(':proximity_alert_triggered', $message->getProximityAlertTriggered());
1083 6
            $sth->bindValue(':reply_markup', $message->getReplyMarkup());
1084
1085 6
            return $sth->execute();
1086
        } catch (PDOException $e) {
1087
            throw new TelegramException($e->getMessage());
1088
        }
1089
    }
1090
1091
    /**
1092
     * Insert Edited Message request in db
1093
     *
1094
     * @param Message $edited_message
1095
     *
1096
     * @return bool If the insert was successful
1097
     * @throws TelegramException
1098
     */
1099
    public static function insertEditedMessageRequest(Message $edited_message): bool
1100
    {
1101
        if (!self::isDbConnected()) {
1102
            return false;
1103
        }
1104
1105
        try {
1106
            $edit_date = self::getTimestamp($edited_message->getEditDate());
1107
1108
            // Insert chat
1109
            $chat = $edited_message->getChat();
1110
            self::insertChat($chat, $edit_date);
1111
1112
            // Insert user and the relation with the chat
1113
            if ($user = $edited_message->getFrom()) {
1114
                self::insertUser($user, $edit_date, $chat);
1115
            }
1116
1117
            $sth = self::$pdo->prepare('
1118
                INSERT IGNORE INTO `' . TB_EDITED_MESSAGE . '`
1119
                (`chat_id`, `message_id`, `user_id`, `edit_date`, `text`, `entities`, `caption`)
1120
                VALUES
1121
                (:chat_id, :message_id, :user_id, :edit_date, :text, :entities, :caption)
1122
            ');
1123
1124
            $user_id = $user ? $user->getId() : null;
0 ignored issues
show
introduced by
$user is of type Longman\TelegramBot\Entities\User, thus it always evaluated to true.
Loading history...
1125
1126
            $sth->bindValue(':chat_id', $chat->getId());
1127
            $sth->bindValue(':message_id', $edited_message->getMessageId());
1128
            $sth->bindValue(':user_id', $user_id);
1129
            $sth->bindValue(':edit_date', $edit_date);
1130
            $sth->bindValue(':text', $edited_message->getText());
1131
            $sth->bindValue(':entities', self::entitiesArrayToJson($edited_message->getEntities() ?: []));
1132
            $sth->bindValue(':caption', $edited_message->getCaption());
1133
1134
            return $sth->execute();
1135
        } catch (PDOException $e) {
1136
            throw new TelegramException($e->getMessage());
1137
        }
1138
    }
1139
1140
    /**
1141
     * Select Groups, Supergroups, Channels and/or single user Chats (also by ID or text)
1142
     *
1143
     * @param $select_chats_params
1144
     *
1145
     * @return array|bool
1146
     * @throws TelegramException
1147
     */
1148
    public static function selectChats($select_chats_params)
1149
    {
1150
        if (!self::isDbConnected()) {
1151
            return false;
1152
        }
1153
1154
        // Set defaults for omitted values.
1155
        $select = array_merge([
1156
            'groups'      => true,
1157
            'supergroups' => true,
1158
            'channels'    => true,
1159
            'users'       => true,
1160
            'date_from'   => null,
1161
            'date_to'     => null,
1162
            'chat_id'     => null,
1163
            'text'        => null,
1164
            'language'    => null,
1165
        ], $select_chats_params);
1166
1167
        if (!$select['groups'] && !$select['users'] && !$select['supergroups'] && !$select['channels']) {
1168
            return false;
1169
        }
1170
1171
        try {
1172
            $query = '
1173
                SELECT * ,
1174
                ' . TB_CHAT . '.`id` AS `chat_id`,
1175
                ' . TB_CHAT . '.`username` AS `chat_username`,
1176
                ' . TB_CHAT . '.`created_at` AS `chat_created_at`,
1177
                ' . TB_CHAT . '.`updated_at` AS `chat_updated_at`
1178
            ';
1179
            if ($select['users']) {
1180
                $query .= '
1181
                    , ' . TB_USER . '.`id` AS `user_id`
1182
                    FROM `' . TB_CHAT . '`
1183
                    LEFT JOIN `' . TB_USER . '`
1184
                    ON ' . TB_CHAT . '.`id`=' . TB_USER . '.`id`
1185
                ';
1186
            } else {
1187
                $query .= 'FROM `' . TB_CHAT . '`';
1188
            }
1189
1190
            // Building parts of query
1191
            $where  = [];
1192
            $tokens = [];
1193
1194
            if (!$select['groups'] || !$select['users'] || !$select['supergroups'] || !$select['channels']) {
1195
                $chat_or_user = [];
1196
1197
                $select['groups'] && $chat_or_user[] = TB_CHAT . '.`type` = "group"';
1198
                $select['supergroups'] && $chat_or_user[] = TB_CHAT . '.`type` = "supergroup"';
1199
                $select['channels'] && $chat_or_user[] = TB_CHAT . '.`type` = "channel"';
1200
                $select['users'] && $chat_or_user[] = TB_CHAT . '.`type` = "private"';
1201
1202
                $where[] = '(' . implode(' OR ', $chat_or_user) . ')';
1203
            }
1204
1205
            if (null !== $select['date_from']) {
1206
                $where[]              = TB_CHAT . '.`updated_at` >= :date_from';
1207
                $tokens[':date_from'] = $select['date_from'];
1208
            }
1209
1210
            if (null !== $select['date_to']) {
1211
                $where[]            = TB_CHAT . '.`updated_at` <= :date_to';
1212
                $tokens[':date_to'] = $select['date_to'];
1213
            }
1214
1215
            if (null !== $select['chat_id']) {
1216
                $where[]            = TB_CHAT . '.`id` = :chat_id';
1217
                $tokens[':chat_id'] = $select['chat_id'];
1218
            }
1219
1220
            if ($select['users'] && null !== $select['language']) {
1221
                $where[]             = TB_USER . '.`language_code` = :language';
1222
                $tokens[':language'] = $select['language'];
1223
            }
1224
1225
            if (null !== $select['text']) {
1226
                $text_like = '%' . strtolower($select['text']) . '%';
1227
                if ($select['users']) {
1228
                    $where[]          = '(
1229
                        LOWER(' . TB_CHAT . '.`title`) LIKE :text1
1230
                        OR LOWER(' . TB_USER . '.`first_name`) LIKE :text2
1231
                        OR LOWER(' . TB_USER . '.`last_name`) LIKE :text3
1232
                        OR LOWER(' . TB_USER . '.`username`) LIKE :text4
1233
                    )';
1234
                    $tokens[':text1'] = $text_like;
1235
                    $tokens[':text2'] = $text_like;
1236
                    $tokens[':text3'] = $text_like;
1237
                    $tokens[':text4'] = $text_like;
1238
                } else {
1239
                    $where[]         = 'LOWER(' . TB_CHAT . '.`title`) LIKE :text';
1240
                    $tokens[':text'] = $text_like;
1241
                }
1242
            }
1243
1244
            if (!empty($where)) {
1245
                $query .= ' WHERE ' . implode(' AND ', $where);
1246
            }
1247
1248
            $query .= ' ORDER BY ' . TB_CHAT . '.`updated_at` ASC';
1249
1250
            $sth = self::$pdo->prepare($query);
1251
            $sth->execute($tokens);
1252
1253
            return $sth->fetchAll(PDO::FETCH_ASSOC);
1254
        } catch (PDOException $e) {
1255
            throw new TelegramException($e->getMessage());
1256
        }
1257
    }
1258
1259
    /**
1260
     * Get Telegram API request count for current chat / message
1261
     *
1262
     * @param int|null    $chat_id
1263
     * @param string|null $inline_message_id
1264
     *
1265
     * @return array|bool Array containing TOTAL and CURRENT fields or false on invalid arguments
1266
     * @throws TelegramException
1267
     */
1268
    public static function getTelegramRequestCount(int $chat_id = null, string $inline_message_id = null)
1269
    {
1270
        if (!self::isDbConnected()) {
1271
            return false;
1272
        }
1273
1274
        try {
1275
            $sth = self::$pdo->prepare('SELECT
1276
                (SELECT COUNT(DISTINCT `chat_id`) FROM `' . TB_REQUEST_LIMITER . '` WHERE `created_at` >= :created_at_1) AS LIMIT_PER_SEC_ALL,
1277
                (SELECT COUNT(*) FROM `' . TB_REQUEST_LIMITER . '` WHERE `created_at` >= :created_at_2 AND ((`chat_id` = :chat_id_1 AND `inline_message_id` IS NULL) OR (`inline_message_id` = :inline_message_id AND `chat_id` IS NULL))) AS LIMIT_PER_SEC,
1278
                (SELECT COUNT(*) FROM `' . TB_REQUEST_LIMITER . '` WHERE `created_at` >= :created_at_minute AND `chat_id` = :chat_id_2) AS LIMIT_PER_MINUTE
1279
            ');
1280
1281
            $date        = self::getTimestamp();
1282
            $date_minute = self::getTimestamp(strtotime('-1 minute'));
1283
1284
            $sth->bindValue(':chat_id_1', $chat_id);
1285
            $sth->bindValue(':chat_id_2', $chat_id);
1286
            $sth->bindValue(':inline_message_id', $inline_message_id);
1287
            $sth->bindValue(':created_at_1', $date);
1288
            $sth->bindValue(':created_at_2', $date);
1289
            $sth->bindValue(':created_at_minute', $date_minute);
1290
1291
            $sth->execute();
1292
1293
            return $sth->fetch();
1294
        } catch (PDOException $e) {
1295
            throw new TelegramException($e->getMessage());
1296
        }
1297
    }
1298
1299
    /**
1300
     * Insert Telegram API request in db
1301
     *
1302
     * @param string $method
1303
     * @param array  $data
1304
     *
1305
     * @return bool If the insert was successful
1306
     * @throws TelegramException
1307
     */
1308
    public static function insertTelegramRequest(string $method, array $data): bool
1309
    {
1310
        if (!self::isDbConnected()) {
1311
            return false;
1312
        }
1313
1314
        try {
1315
            $sth = self::$pdo->prepare('INSERT INTO `' . TB_REQUEST_LIMITER . '`
1316
                (`method`, `chat_id`, `inline_message_id`, `created_at`)
1317
                VALUES
1318
                (:method, :chat_id, :inline_message_id, :created_at);
1319
            ');
1320
1321
            $chat_id           = $data['chat_id'] ?? null;
1322
            $inline_message_id = $data['inline_message_id'] ?? null;
1323
1324
            $sth->bindValue(':chat_id', $chat_id);
1325
            $sth->bindValue(':inline_message_id', $inline_message_id);
1326
            $sth->bindValue(':method', $method);
1327
            $sth->bindValue(':created_at', self::getTimestamp());
1328
1329
            return $sth->execute();
1330
        } catch (PDOException $e) {
1331
            throw new TelegramException($e->getMessage());
1332
        }
1333
    }
1334
1335
    /**
1336
     * Bulk update the entries of any table
1337
     *
1338
     * @param string $table
1339
     * @param array  $fields_values
1340
     * @param array  $where_fields_values
1341
     *
1342
     * @return bool
1343
     * @throws TelegramException
1344
     */
1345 3
    public static function update(string $table, array $fields_values, array $where_fields_values): bool
1346
    {
1347 3
        if (empty($fields_values) || !self::isDbConnected()) {
1348
            return false;
1349
        }
1350
1351
        try {
1352
            // Building parts of query
1353 3
            $tokens = $fields = $where = [];
1354
1355
            // Fields with values to update
1356 3
            foreach ($fields_values as $field => $value) {
1357 3
                $token          = ':' . count($tokens);
1358 3
                $fields[]       = "`{$field}` = {$token}";
1359 3
                $tokens[$token] = $value;
1360
            }
1361
1362
            // Where conditions
1363 3
            foreach ($where_fields_values as $field => $value) {
1364 3
                $token          = ':' . count($tokens);
1365 3
                $where[]        = "`{$field}` = {$token}";
1366 3
                $tokens[$token] = $value;
1367
            }
1368
1369 3
            $sql = 'UPDATE `' . $table . '` SET ' . implode(', ', $fields);
1370 3
            $sql .= count($where) > 0 ? ' WHERE ' . implode(' AND ', $where) : '';
1371
1372 3
            return self::$pdo->prepare($sql)->execute($tokens);
1373
        } catch (PDOException $e) {
1374
            throw new TelegramException($e->getMessage());
1375
        }
1376
    }
1377
}
1378