Completed
Push — 1088-log_request_data ( c1a72a...add4b8 )
by Armando
02:26 queued 25s
created

DB::insertTelegramUpdate()   C

Complexity

Conditions 14
Paths 18

Size

Total Lines 48
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 210

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 14
eloc 23
c 4
b 0
f 0
nc 18
nop 13
dl 0
loc 48
ccs 0
cts 23
cp 0
crap 210
rs 6.2666

How to fix   Complexity    Many Parameters   

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:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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 = null,
75
        $encoding = 'utf8mb4'
76
    ) {
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
        $external_pdo_connection,
118
        Telegram $telegram,
119
        $table_prefix = null
120
    ) {
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()
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()
170
    {
171 9
        return self::$pdo !== null;
172
    }
173
174
    /**
175
     * Get the PDO object of the connected database
176
     *
177
     * @return PDO
178
     */
179
    public static function getPdo()
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($limit = null, $id = null)
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 !== null) {
206
                $sql .= ' WHERE `id` = :id';
207
            } else {
208
                $sql .= ' ORDER BY `id` DESC';
209
            }
210
211
            if ($limit !== null) {
212
                $sql .= ' LIMIT :limit';
213
            }
214
215
            $sth = self::$pdo->prepare($sql);
216
217
            if ($limit !== null) {
218
                $sth->bindValue(':limit', $limit, PDO::PARAM_INT);
219
            }
220
            if ($id !== null) {
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($limit = null)
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 !== null) {
254
                $sql .= ' LIMIT :limit';
255
            }
256
257
            $sth = self::$pdo->prepare($sql);
258
259
            if ($limit !== null) {
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 $time Unix timestamp (if empty, current timestamp is used)
275
     *
276
     * @return string
277
     */
278 7
    protected static function getTimestamp($time = null)
279
    {
280 7
        return date('Y-m-d H:i:s', $time ?: 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|null $entities
289
     * @param mixed      $default
290
     *
291
     * @return mixed
292
     */
293 6
    public static function entitiesArrayToJson($entities, $default = null)
294
    {
295 6
        if (!is_array($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 string      $update_id
311
     * @param string|null $chat_id
312
     * @param string|null $message_id
313
     * @param string|null $edited_message_id
314
     * @param string|null $channel_post_id
315
     * @param string|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
        $update_id,
329
        $chat_id = null,
330
        $message_id = null,
331
        $edited_message_id = null,
332
        $channel_post_id = null,
333
        $edited_channel_post_id = null,
334
        $inline_query_id = null,
335
        $chosen_inline_result_id = null,
336
        $callback_query_id = null,
337
        $shipping_query_id = null,
338
        $pre_checkout_query_id = null,
339
        $poll_id = null,
340
        $poll_answer_poll_id = null
341
    ) {
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 $date
383
     * @param Chat   $chat
384
     *
385
     * @return bool If the insert was successful
386
     * @throws TelegramException
387
     */
388 6
    public static function insertUser(User $user, $date = null, Chat $chat = null)
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 $date
451
     * @param string $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, $date = null, $migrate_to_chat_id = null)
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)
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 = 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 = 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)
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)
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)
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)
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)
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)
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() ?: null));
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() ?: null));
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)
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)
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
        // Insert user and the relation with the chat
942 6
        if ($user = $message->getFrom()) {
943 6
            self::insertUser($user, $date, $chat);
944
        }
945
946
        // Insert the forwarded message user in users table
947 6
        $forward_date = $message->getForwardDate() ? self::getTimestamp($message->getForwardDate()) : null;
948
949 6
        if ($forward_from = $message->getForwardFrom()) {
950
            self::insertUser($forward_from);
951
            $forward_from = $forward_from->getId();
952
        }
953 6
        if ($forward_from_chat = $message->getForwardFromChat()) {
954
            self::insertChat($forward_from_chat);
955
            $forward_from_chat = $forward_from_chat->getId();
956
        }
957
958
        // New and left chat member
959 6
        $new_chat_members_ids = null;
960 6
        $left_chat_member_id  = null;
961
962 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

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