Completed
Push — master ( 466468...8588b9 )
by Armando
02:38 queued 36s
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\ReplyToMessage;
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
            $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
            'request_limiter',
150
            'shipping_query',
151
            'telegram_update',
152
            'user',
153
            'user_chat',
154
        ];
155 9
        foreach ($tables as $table) {
156 9
            $table_name = 'TB_' . strtoupper($table);
157 9
            if (!defined($table_name)) {
158 1
                define($table_name, self::$table_prefix . $table);
159
            }
160
        }
161 9
    }
162
163
    /**
164
     * Check if database connection has been created
165
     *
166
     * @return bool
167
     */
168 9
    public static function isDbConnected()
169
    {
170 9
        return self::$pdo !== null;
171
    }
172
173
    /**
174
     * Get the PDO object of the connected database
175
     *
176
     * @return PDO
177
     */
178
    public static function getPdo()
179
    {
180
        return self::$pdo;
181
    }
182
183
    /**
184
     * Fetch update(s) from DB
185
     *
186
     * @param int    $limit Limit the number of updates to fetch
187
     * @param string $id    Check for unique update id
188
     *
189
     * @return array|bool Fetched data or false if not connected
190
     * @throws TelegramException
191
     */
192
    public static function selectTelegramUpdate($limit = null, $id = null)
193
    {
194
        if (!self::isDbConnected()) {
195
            return false;
196
        }
197
198
        try {
199
            $sql = '
200
                SELECT `id`
201
                FROM `' . TB_TELEGRAM_UPDATE . '`
202
            ';
203
204
            if ($id !== null) {
205
                $sql .= ' WHERE `id` = :id';
206
            } else {
207
                $sql .= ' ORDER BY `id` DESC';
208
            }
209
210
            if ($limit !== null) {
211
                $sql .= ' LIMIT :limit';
212
            }
213
214
            $sth = self::$pdo->prepare($sql);
215
216
            if ($limit !== null) {
217
                $sth->bindValue(':limit', $limit, PDO::PARAM_INT);
218
            }
219
            if ($id !== null) {
220
                $sth->bindValue(':id', $id);
221
            }
222
223
            $sth->execute();
224
225
            return $sth->fetchAll(PDO::FETCH_ASSOC);
226
        } catch (PDOException $e) {
227
            throw new TelegramException($e->getMessage());
228
        }
229
    }
230
231
    /**
232
     * Fetch message(s) from DB
233
     *
234
     * @param int $limit Limit the number of messages to fetch
235
     *
236
     * @return array|bool Fetched data or false if not connected
237
     * @throws TelegramException
238
     */
239
    public static function selectMessages($limit = null)
240
    {
241
        if (!self::isDbConnected()) {
242
            return false;
243
        }
244
245
        try {
246
            $sql = '
247
                SELECT *
248
                FROM `' . TB_MESSAGE . '`
249
                ORDER BY `id` DESC
250
            ';
251
252
            if ($limit !== null) {
253
                $sql .= ' LIMIT :limit';
254
            }
255
256
            $sth = self::$pdo->prepare($sql);
257
258
            if ($limit !== null) {
259
                $sth->bindValue(':limit', $limit, PDO::PARAM_INT);
260
            }
261
262
            $sth->execute();
263
264
            return $sth->fetchAll(PDO::FETCH_ASSOC);
265
        } catch (PDOException $e) {
266
            throw new TelegramException($e->getMessage());
267
        }
268
    }
269
270
    /**
271
     * Convert from unix timestamp to timestamp
272
     *
273
     * @param int $time Unix timestamp (if empty, current timestamp is used)
274
     *
275
     * @return string
276
     */
277 7
    protected static function getTimestamp($time = null)
278
    {
279 7
        return date('Y-m-d H:i:s', $time ?: time());
280
    }
281
282
    /**
283
     * Convert array of Entity items to a JSON array
284
     *
285
     * @todo Find a better way, as json_* functions are very heavy
286
     *
287
     * @param array|null $entities
288
     * @param mixed      $default
289
     *
290
     * @return mixed
291
     */
292 6
    public static function entitiesArrayToJson($entities, $default = null)
293
    {
294 6
        if (!is_array($entities)) {
295 6
            return $default;
296
        }
297
298
        // Convert each Entity item into an object based on its JSON reflection
299
        $json_entities = array_map(function ($entity) {
300
            return json_decode($entity, true);
301
        }, $entities);
302
303
        return json_encode($json_entities);
304
    }
305
306
    /**
307
     * Insert entry to telegram_update table
308
     *
309
     * @param string      $update_id
310
     * @param string|null $chat_id
311
     * @param string|null $message_id
312
     * @param string|null $edited_message_id
313
     * @param string|null $channel_post_id
314
     * @param string|null $edited_channel_post_id
315
     * @param string|null $inline_query_id
316
     * @param string|null $chosen_inline_result_id
317
     * @param string|null $callback_query_id
318
     * @param string|null $shipping_query_id
319
     * @param string|null $pre_checkout_query_id
320
     * @param string|null $poll_id
321
     *
322
     * @return bool If the insert was successful
323
     * @throws TelegramException
324
     */
325
    protected static function insertTelegramUpdate(
326
        $update_id,
327
        $chat_id = null,
328
        $message_id = null,
329
        $edited_message_id = null,
330
        $channel_post_id = null,
331
        $edited_channel_post_id = null,
332
        $inline_query_id = null,
333
        $chosen_inline_result_id = null,
334
        $callback_query_id = null,
335
        $shipping_query_id = null,
336
        $pre_checkout_query_id = null,
337
        $poll_id = null
338
    ) {
339
        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) {
340
            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 are all null');
341
        }
342
343
        if (!self::isDbConnected()) {
344
            return false;
345
        }
346
347
        try {
348
            $sth = self::$pdo->prepare('
349
                INSERT IGNORE INTO `' . TB_TELEGRAM_UPDATE . '`
350
                (`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`)
351
                VALUES
352
                (: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)
353
            ');
354
355
            $sth->bindValue(':id', $update_id);
356
            $sth->bindValue(':chat_id', $chat_id);
357
            $sth->bindValue(':message_id', $message_id);
358
            $sth->bindValue(':edited_message_id', $edited_message_id);
359
            $sth->bindValue(':channel_post_id', $channel_post_id);
360
            $sth->bindValue(':edited_channel_post_id', $edited_channel_post_id);
361
            $sth->bindValue(':inline_query_id', $inline_query_id);
362
            $sth->bindValue(':chosen_inline_result_id', $chosen_inline_result_id);
363
            $sth->bindValue(':callback_query_id', $callback_query_id);
364
            $sth->bindValue(':shipping_query_id', $shipping_query_id);
365
            $sth->bindValue(':pre_checkout_query_id', $pre_checkout_query_id);
366
            $sth->bindValue(':poll_id', $poll_id);
367
368
            return $sth->execute();
369
        } catch (PDOException $e) {
370
            throw new TelegramException($e->getMessage());
371
        }
372
    }
373
374
    /**
375
     * Insert users and save their connection to chats
376
     *
377
     * @param User   $user
378
     * @param string $date
379
     * @param Chat   $chat
380
     *
381
     * @return bool If the insert was successful
382
     * @throws TelegramException
383
     */
384 6
    public static function insertUser(User $user, $date = null, Chat $chat = null)
385
    {
386 6
        if (!self::isDbConnected()) {
387
            return false;
388
        }
389
390
        try {
391 6
            $sth = self::$pdo->prepare('
392 6
                INSERT INTO `' . TB_USER . '`
393
                (`id`, `is_bot`, `username`, `first_name`, `last_name`, `language_code`, `created_at`, `updated_at`)
394
                VALUES
395
                (:id, :is_bot, :username, :first_name, :last_name, :language_code, :created_at, :updated_at)
396
                ON DUPLICATE KEY UPDATE
397
                    `is_bot`         = VALUES(`is_bot`),
398
                    `username`       = VALUES(`username`),
399
                    `first_name`     = VALUES(`first_name`),
400
                    `last_name`      = VALUES(`last_name`),
401
                    `language_code`  = VALUES(`language_code`),
402
                    `updated_at`     = VALUES(`updated_at`)
403
            ');
404
405 6
            $sth->bindValue(':id', $user->getId());
406 6
            $sth->bindValue(':is_bot', $user->getIsBot(), PDO::PARAM_INT);
407 6
            $sth->bindValue(':username', $user->getUsername());
408 6
            $sth->bindValue(':first_name', $user->getFirstName());
409 6
            $sth->bindValue(':last_name', $user->getLastName());
410 6
            $sth->bindValue(':language_code', $user->getLanguageCode());
411 6
            $date = $date ?: self::getTimestamp();
412 6
            $sth->bindValue(':created_at', $date);
413 6
            $sth->bindValue(':updated_at', $date);
414
415 6
            $status = $sth->execute();
416
        } catch (PDOException $e) {
417
            throw new TelegramException($e->getMessage());
418
        }
419
420
        // Also insert the relationship to the chat into the user_chat table
421 6
        if ($chat instanceof Chat) {
422
            try {
423 6
                $sth = self::$pdo->prepare('
424 6
                    INSERT IGNORE INTO `' . TB_USER_CHAT . '`
425
                    (`user_id`, `chat_id`)
426
                    VALUES
427
                    (:user_id, :chat_id)
428
                ');
429
430 6
                $sth->bindValue(':user_id', $user->getId());
431 6
                $sth->bindValue(':chat_id', $chat->getId());
432
433 6
                $status = $sth->execute();
434
            } catch (PDOException $e) {
435
                throw new TelegramException($e->getMessage());
436
            }
437
        }
438
439 6
        return $status;
440
    }
441
442
    /**
443
     * Insert chat
444
     *
445
     * @param Chat   $chat
446
     * @param string $date
447
     * @param string $migrate_to_chat_id
448
     *
449
     * @return bool If the insert was successful
450
     * @throws TelegramException
451
     */
452 6
    public static function insertChat(Chat $chat, $date = null, $migrate_to_chat_id = null)
453
    {
454 6
        if (!self::isDbConnected()) {
455
            return false;
456
        }
457
458
        try {
459 6
            $sth = self::$pdo->prepare('
460 6
                INSERT IGNORE INTO `' . TB_CHAT . '`
461
                (`id`, `type`, `title`, `username`, `first_name`, `last_name`, `all_members_are_administrators`, `created_at` ,`updated_at`, `old_id`)
462
                VALUES
463
                (:id, :type, :title, :username, :first_name, :last_name, :all_members_are_administrators, :created_at, :updated_at, :old_id)
464
                ON DUPLICATE KEY UPDATE
465
                    `type`                           = VALUES(`type`),
466
                    `title`                          = VALUES(`title`),
467
                    `username`                       = VALUES(`username`),
468
                    `first_name`                     = VALUES(`first_name`),
469
                    `last_name`                      = VALUES(`last_name`),
470
                    `all_members_are_administrators` = VALUES(`all_members_are_administrators`),
471
                    `updated_at`                     = VALUES(`updated_at`)
472
            ');
473
474 6
            $chat_id   = $chat->getId();
475 6
            $chat_type = $chat->getType();
476
477 6
            if ($migrate_to_chat_id !== null) {
478
                $chat_type = 'supergroup';
479
480
                $sth->bindValue(':id', $migrate_to_chat_id);
481
                $sth->bindValue(':old_id', $chat_id);
482
            } else {
483 6
                $sth->bindValue(':id', $chat_id);
484 6
                $sth->bindValue(':old_id', $migrate_to_chat_id);
485
            }
486
487 6
            $sth->bindValue(':type', $chat_type);
488 6
            $sth->bindValue(':title', $chat->getTitle());
489 6
            $sth->bindValue(':username', $chat->getUsername());
490 6
            $sth->bindValue(':first_name', $chat->getFirstName());
491 6
            $sth->bindValue(':last_name', $chat->getLastName());
492 6
            $sth->bindValue(':all_members_are_administrators', $chat->getAllMembersAreAdministrators(), PDO::PARAM_INT);
0 ignored issues
show
Bug introduced by
The method getAllMembersAreAdministrators() does not exist on Longman\TelegramBot\Entities\Chat. 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

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

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