Passed
Push — api-7.0 ( 6ac789 )
by Armando
08:20
created

DB::insertTelegramUpdate()   D

Complexity

Conditions 19
Paths 23

Size

Total Lines 70
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 19
eloc 28
c 0
b 0
f 0
nc 23
nop 18
dl 0
loc 70
rs 4.5166

How to fix   Long Method    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\ChatJoinRequest;
18
use Longman\TelegramBot\Entities\ChatMemberUpdated;
19
use Longman\TelegramBot\Entities\ChosenInlineResult;
20
use Longman\TelegramBot\Entities\InlineQuery;
21
use Longman\TelegramBot\Entities\Message;
22
use Longman\TelegramBot\Entities\MessageReactionCountUpdated;
23
use Longman\TelegramBot\Entities\MessageReactionUpdated;
24
use Longman\TelegramBot\Entities\Payments\PreCheckoutQuery;
25
use Longman\TelegramBot\Entities\Payments\ShippingQuery;
26
use Longman\TelegramBot\Entities\Poll;
27
use Longman\TelegramBot\Entities\PollAnswer;
28
use Longman\TelegramBot\Entities\Update;
29
use Longman\TelegramBot\Entities\User;
30
use Longman\TelegramBot\Exception\TelegramException;
31
use PDO;
32
use PDOException;
33
34
class DB
35
{
36
    /**
37
     * MySQL credentials
38
     *
39
     * @var array
40
     */
41
    protected static $mysql_credentials = [];
42
43
    /**
44
     * PDO object
45
     *
46
     * @var PDO
47
     */
48
    protected static $pdo;
49
50
    /**
51
     * Table prefix
52
     *
53
     * @var string
54
     */
55
    protected static $table_prefix;
56
57
    /**
58
     * Telegram class object
59
     *
60
     * @var Telegram
61
     */
62
    protected static $telegram;
63
64
    /**
65
     * Initialize
66
     *
67
     * @param array    $credentials  Database connection details
68
     * @param Telegram $telegram     Telegram object to connect with this object
69
     * @param string   $table_prefix Table prefix
70
     * @param string   $encoding     Database character encoding
71
     *
72
     * @return PDO PDO database object
73
     * @throws TelegramException
74
     */
75
    public static function initialize(
76
        array $credentials,
77
        Telegram $telegram,
78
        $table_prefix = '',
79
        $encoding = 'utf8mb4'
80
    ): PDO {
81
        if (empty($credentials)) {
82
            throw new TelegramException('MySQL credentials not provided!');
83
        }
84
        if (isset($credentials['unix_socket'])) {
85
            $dsn = 'mysql:unix_socket=' . $credentials['unix_socket'];
86
        } else {
87
            $dsn = 'mysql:host=' . $credentials['host'];
88
        }
89
        $dsn .= ';dbname=' . $credentials['database'];
90
91
        if (!empty($credentials['port'])) {
92
            $dsn .= ';port=' . $credentials['port'];
93
        }
94
95
        $options = [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . $encoding];
96
        try {
97
            $pdo = new PDO($dsn, $credentials['user'], $credentials['password'], $options);
98
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
99
        } catch (PDOException $e) {
100
            throw new TelegramException($e->getMessage());
101
        }
102
103
        self::$pdo               = $pdo;
104
        self::$telegram          = $telegram;
105
        self::$mysql_credentials = $credentials;
106
        self::$table_prefix      = $table_prefix;
107
108
        self::defineTables();
109
110
        return self::$pdo;
111
    }
112
113
    /**
114
     * External Initialize
115
     *
116
     * Let you use the class with an external already existing Pdo Mysql connection.
117
     *
118
     * @param PDO      $external_pdo_connection PDO database object
119
     * @param Telegram $telegram                Telegram object to connect with this object
120
     * @param string   $table_prefix            Table prefix
121
     *
122
     * @return PDO PDO database object
123
     * @throws TelegramException
124
     */
125
    public static function externalInitialize(
126
        PDO $external_pdo_connection,
127
        Telegram $telegram,
128
        string $table_prefix = ''
129
    ): PDO {
130
        if ($external_pdo_connection === null) {
131
            throw new TelegramException('MySQL external connection not provided!');
132
        }
133
134
        self::$pdo               = $external_pdo_connection;
135
        self::$telegram          = $telegram;
136
        self::$mysql_credentials = [];
137
        self::$table_prefix      = $table_prefix;
138
139
        self::defineTables();
140
141
        return self::$pdo;
142
    }
143
144
    /**
145
     * Define all the tables with the proper prefix
146
     */
147
    protected static function defineTables(): void
148
    {
149
        $tables = [
150
            'callback_query',
151
            'chat',
152
            'chat_join_request',
153
            'chat_member_updated',
154
            'chosen_inline_result',
155
            'edited_message',
156
            'inline_query',
157
            'message',
158
            'message_reaction',
159
            'message_reaction_count',
160
            'poll',
161
            'poll_answer',
162
            'pre_checkout_query',
163
            'request_limiter',
164
            'shipping_query',
165
            'telegram_update',
166
            'user',
167
            'user_chat',
168
        ];
169
        foreach ($tables as $table) {
170
            $table_name = 'TB_' . strtoupper($table);
171
            if (!defined($table_name)) {
172
                define($table_name, self::$table_prefix . $table);
173
            }
174
        }
175
    }
176
177
    /**
178
     * Check if database connection has been created
179
     *
180
     * @return bool
181
     */
182
    public static function isDbConnected(): bool
183
    {
184
        return self::$pdo !== null;
185
    }
186
187
    /**
188
     * Get the PDO object of the connected database
189
     *
190
     * @return PDO|null
191
     */
192
    public static function getPdo(): ?PDO
193
    {
194
        return self::$pdo;
195
    }
196
197
    /**
198
     * Fetch update(s) from DB
199
     *
200
     * @param int    $limit Limit the number of updates to fetch
201
     * @param string $id    Check for unique update id
202
     *
203
     * @return array|bool Fetched data or false if not connected
204
     * @throws TelegramException
205
     */
206
    public static function selectTelegramUpdate(int $limit = 0, string $id = '')
207
    {
208
        if (!self::isDbConnected()) {
209
            return false;
210
        }
211
212
        try {
213
            $sql = '
214
                SELECT `id`
215
                FROM `' . TB_TELEGRAM_UPDATE . '`
216
            ';
217
218
            if ($id !== '') {
219
                $sql .= ' WHERE `id` = :id';
220
            } else {
221
                $sql .= ' ORDER BY `id` DESC';
222
            }
223
224
            if ($limit > 0) {
225
                $sql .= ' LIMIT :limit';
226
            }
227
228
            $sth = self::$pdo->prepare($sql);
229
230
            if ($limit > 0) {
231
                $sth->bindValue(':limit', $limit, PDO::PARAM_INT);
232
            }
233
            if ($id !== '') {
234
                $sth->bindValue(':id', $id);
235
            }
236
237
            $sth->execute();
238
239
            return $sth->fetchAll(PDO::FETCH_ASSOC);
240
        } catch (PDOException $e) {
241
            throw new TelegramException($e->getMessage());
242
        }
243
    }
244
245
    /**
246
     * Fetch message(s) from DB
247
     *
248
     * @param int $limit Limit the number of messages to fetch
249
     *
250
     * @return array|bool Fetched data or false if not connected
251
     * @throws TelegramException
252
     */
253
    public static function selectMessages(int $limit = 0)
254
    {
255
        if (!self::isDbConnected()) {
256
            return false;
257
        }
258
259
        try {
260
            $sql = '
261
                SELECT *
262
                FROM `' . TB_MESSAGE . '`
263
                ORDER BY `id` DESC
264
            ';
265
266
            if ($limit > 0) {
267
                $sql .= ' LIMIT :limit';
268
            }
269
270
            $sth = self::$pdo->prepare($sql);
271
272
            if ($limit > 0) {
273
                $sth->bindValue(':limit', $limit, PDO::PARAM_INT);
274
            }
275
276
            $sth->execute();
277
278
            return $sth->fetchAll(PDO::FETCH_ASSOC);
279
        } catch (PDOException $e) {
280
            throw new TelegramException($e->getMessage());
281
        }
282
    }
283
284
    /**
285
     * Convert from unix timestamp to timestamp
286
     *
287
     * @param ?int $unixtime Unix timestamp (if empty, current timestamp is used)
288
     *
289
     * @return string
290
     */
291
    protected static function getTimestamp(?int $unixtime = null): string
292
    {
293
        return date('Y-m-d H:i:s', $unixtime ?? time());
294
    }
295
296
    /**
297
     * Convert array of Entity items to a JSON array
298
     *
299
     * @todo Find a better way, as json_* functions are very heavy
300
     *
301
     * @param array $entities
302
     * @param mixed $default
303
     *
304
     * @return mixed
305
     */
306
    public static function entitiesArrayToJson(array $entities, $default = null)
307
    {
308
        if (empty($entities)) {
309
            return $default;
310
        }
311
312
        // Convert each Entity item into an object based on its JSON reflection
313
        $json_entities = array_map(function ($entity) {
314
            return json_decode($entity, true);
315
        }, $entities);
316
317
        return json_encode($json_entities);
318
    }
319
320
    /**
321
     * Insert entry to telegram_update table
322
     *
323
     * @throws TelegramException
324
     */
325
    protected static function insertTelegramUpdate(
326
        int $update_id,
327
        ?int $chat_id = null,
328
        ?int $message_id = null,
329
        ?int $edited_message_id = null,
330
        ?int $channel_post_id = null,
331
        ?int $edited_channel_post_id = null,
332
        ?string $message_reaction_id = null,
333
        ?string $message_reaction_count_id = null,
334
        ?string $inline_query_id = null,
335
        ?string $chosen_inline_result_id = null,
336
        ?string $callback_query_id = null,
337
        ?string $shipping_query_id = null,
338
        ?string $pre_checkout_query_id = null,
339
        ?string $poll_id = null,
340
        ?string $poll_answer_poll_id = null,
341
        ?string $my_chat_member_updated_id = null,
342
        ?string $chat_member_updated_id = null,
343
        ?string $chat_join_request_id = null
344
    ): ?bool {
345
        if ($message_id === null && $edited_message_id === null && $channel_post_id === null && $edited_channel_post_id === null && $message_reaction_id === null && $message_reaction_count_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 && $my_chat_member_updated_id === null && $chat_member_updated_id === null && $chat_join_request_id === null) {
346
            throw new TelegramException('message_id, edited_message_id, channel_post_id, edited_channel_post_id, message_reaction_id, message_reaction_count_id, inline_query_id, chosen_inline_result_id, callback_query_id, shipping_query_id, pre_checkout_query_id, poll_id, poll_answer_poll_id, my_chat_member_updated_id, chat_member_updated_id are all null');
347
        }
348
349
        if (!self::isDbConnected()) {
350
            return false;
351
        }
352
353
        try {
354
            $sth = self::$pdo->prepare('
355
                INSERT IGNORE INTO `' . TB_TELEGRAM_UPDATE . '`
356
                (
357
                    `id`, `chat_id`, `message_id`, `edited_message_id`,
358
                    `channel_post_id`, `edited_channel_post_id`, `message_reaction_id`, `message_reaction_count_id`,
359
                    `inline_query_id`, `chosen_inline_result_id`,
360
                    `callback_query_id`, `shipping_query_id`, `pre_checkout_query_id`,
361
                    `poll_id`, `poll_answer_poll_id`, `my_chat_member_updated_id`, `chat_member_updated_id`,
362
                    `chat_join_request_id`
363
                ) VALUES (
364
                    :id, :chat_id, :message_id, :edited_message_id,
365
                    :channel_post_id, :edited_channel_post_id, :message_reaction_id, :message_reaction_count_id,
366
                    :inline_query_id, :chosen_inline_result_id,
367
                    :callback_query_id, :shipping_query_id, :pre_checkout_query_id,
368
                    :poll_id, :poll_answer_poll_id, :my_chat_member_updated_id, :chat_member_updated_id,
369
                    :chat_join_request_id
370
                )
371
            ');
372
373
            $sth->bindValue(':id', $update_id);
374
            $sth->bindValue(':chat_id', $chat_id);
375
            $sth->bindValue(':message_id', $message_id);
376
            $sth->bindValue(':edited_message_id', $edited_message_id);
377
            $sth->bindValue(':channel_post_id', $channel_post_id);
378
            $sth->bindValue(':edited_channel_post_id', $edited_channel_post_id);
379
            $sth->bindValue(':message_reaction_id', $message_reaction_id);
380
            $sth->bindValue(':message_reaction_count_id', $message_reaction_count_id);
381
            $sth->bindValue(':inline_query_id', $inline_query_id);
382
            $sth->bindValue(':chosen_inline_result_id', $chosen_inline_result_id);
383
            $sth->bindValue(':callback_query_id', $callback_query_id);
384
            $sth->bindValue(':shipping_query_id', $shipping_query_id);
385
            $sth->bindValue(':pre_checkout_query_id', $pre_checkout_query_id);
386
            $sth->bindValue(':poll_id', $poll_id);
387
            $sth->bindValue(':poll_answer_poll_id', $poll_answer_poll_id);
388
            $sth->bindValue(':my_chat_member_updated_id', $my_chat_member_updated_id);
389
            $sth->bindValue(':chat_member_updated_id', $chat_member_updated_id);
390
            $sth->bindValue(':chat_join_request_id', $chat_join_request_id);
391
392
            return $sth->execute();
393
        } catch (PDOException $e) {
394
            throw new TelegramException($e->getMessage());
395
        }
396
    }
397
398
    /**
399
     * Insert users and save their connection to chats
400
     *
401
     * @param User        $user
402
     * @param string|null $date
403
     * @param Chat|null   $chat
404
     *
405
     * @return bool If the insert was successful
406
     * @throws TelegramException
407
     */
408
    public static function insertUser(User $user, ?string $date = null, ?Chat $chat = null): bool
409
    {
410
        if (!self::isDbConnected()) {
411
            return false;
412
        }
413
414
        try {
415
            $sth = self::$pdo->prepare('
416
                INSERT INTO `' . TB_USER . '`
417
                (`id`, `is_bot`, `username`, `first_name`, `last_name`, `language_code`, `is_premium`, `added_to_attachment_menu`, `created_at`, `updated_at`)
418
                VALUES
419
                (:id, :is_bot, :username, :first_name, :last_name, :language_code, :is_premium, :added_to_attachment_menu, :created_at, :updated_at)
420
                ON DUPLICATE KEY UPDATE
421
                    `is_bot`                   = VALUES(`is_bot`),
422
                    `username`                 = VALUES(`username`),
423
                    `first_name`               = VALUES(`first_name`),
424
                    `last_name`                = VALUES(`last_name`),
425
                    `language_code`            = VALUES(`language_code`),
426
                    `is_premium`               = VALUES(`is_premium`),
427
                    `added_to_attachment_menu` = VALUES(`added_to_attachment_menu`),
428
                    `updated_at`               = VALUES(`updated_at`)
429
            ');
430
431
            $sth->bindValue(':id', $user->getId());
432
            $sth->bindValue(':is_bot', $user->getIsBot(), PDO::PARAM_INT);
433
            $sth->bindValue(':username', $user->getUsername());
434
            $sth->bindValue(':first_name', $user->getFirstName());
435
            $sth->bindValue(':last_name', $user->getLastName());
436
            $sth->bindValue(':language_code', $user->getLanguageCode());
437
            $sth->bindValue(':is_premium', $user->getIsPremium(), PDO::PARAM_INT);
438
            $sth->bindValue(':added_to_attachment_menu', $user->getAddedToAttachmentMenu(), PDO::PARAM_INT);
439
            $date = $date ?: self::getTimestamp();
440
            $sth->bindValue(':created_at', $date);
441
            $sth->bindValue(':updated_at', $date);
442
443
            $status = $sth->execute();
444
        } catch (PDOException $e) {
445
            throw new TelegramException($e->getMessage());
446
        }
447
448
        // Also insert the relationship to the chat into the user_chat table
449
        if ($chat) {
450
            try {
451
                $sth = self::$pdo->prepare('
452
                    INSERT IGNORE INTO `' . TB_USER_CHAT . '`
453
                    (`user_id`, `chat_id`)
454
                    VALUES
455
                    (:user_id, :chat_id)
456
                ');
457
458
                $sth->bindValue(':user_id', $user->getId());
459
                $sth->bindValue(':chat_id', $chat->getId());
460
461
                $status = $sth->execute();
462
            } catch (PDOException $e) {
463
                throw new TelegramException($e->getMessage());
464
            }
465
        }
466
467
        return $status;
468
    }
469
470
    /**
471
     * Insert chat
472
     *
473
     * @param Chat        $chat
474
     * @param string|null $date
475
     * @param int|null    $migrate_to_chat_id
476
     *
477
     * @return bool If the insert was successful
478
     * @throws TelegramException
479
     */
480
    public static function insertChat(Chat $chat, ?string $date = null, ?int $migrate_to_chat_id = null): ?bool
481
    {
482
        if (!self::isDbConnected()) {
483
            return false;
484
        }
485
486
        try {
487
            $sth = self::$pdo->prepare('
488
                INSERT IGNORE INTO `' . TB_CHAT . '`
489
                (`id`, `type`, `title`, `username`, `first_name`, `last_name`, `is_forum`, `created_at` ,`updated_at`, `old_id`)
490
                VALUES
491
                (:id, :type, :title, :username, :first_name, :last_name, :is_forum, :created_at, :updated_at, :old_id)
492
                ON DUPLICATE KEY UPDATE
493
                    `type`                           = VALUES(`type`),
494
                    `title`                          = VALUES(`title`),
495
                    `username`                       = VALUES(`username`),
496
                    `first_name`                     = VALUES(`first_name`),
497
                    `last_name`                      = VALUES(`last_name`),
498
                    `is_forum`                       = VALUES(`is_forum`),
499
                    `updated_at`                     = VALUES(`updated_at`)
500
            ');
501
502
            $chat_id   = $chat->getId();
503
            $chat_type = $chat->getType();
504
505
            if ($migrate_to_chat_id !== null) {
506
                $chat_type = 'supergroup';
507
508
                $sth->bindValue(':id', $migrate_to_chat_id);
509
                $sth->bindValue(':old_id', $chat_id);
510
            } else {
511
                $sth->bindValue(':id', $chat_id);
512
                $sth->bindValue(':old_id', $migrate_to_chat_id);
513
            }
514
515
            $sth->bindValue(':type', $chat_type);
516
            $sth->bindValue(':title', $chat->getTitle());
517
            $sth->bindValue(':username', $chat->getUsername());
518
            $sth->bindValue(':first_name', $chat->getFirstName());
519
            $sth->bindValue(':last_name', $chat->getLastName());
520
            $sth->bindValue(':is_forum', $chat->getIsForum());
521
            $date = $date ?: self::getTimestamp();
522
            $sth->bindValue(':created_at', $date);
523
            $sth->bindValue(':updated_at', $date);
524
525
            return $sth->execute();
526
        } catch (PDOException $e) {
527
            throw new TelegramException($e->getMessage());
528
        }
529
    }
530
531
    /**
532
     * Insert request into database
533
     *
534
     * @todo self::$pdo->lastInsertId() - unsafe usage if expected previous insert fails?
535
     *
536
     * @param Update $update
537
     *
538
     * @return bool
539
     * @throws TelegramException
540
     */
541
    public static function insertRequest(Update $update): bool
542
    {
543
        if (!self::isDbConnected()) {
544
            return false;
545
        }
546
547
        $chat_id                   = null;
548
        $message_id                = null;
549
        $edited_message_id         = null;
550
        $channel_post_id           = null;
551
        $edited_channel_post_id    = null;
552
        $message_reaction_id       = null;
553
        $message_reaction_count_id = null;
554
        $inline_query_id           = null;
555
        $chosen_inline_result_id   = null;
556
        $callback_query_id         = null;
557
        $shipping_query_id         = null;
558
        $pre_checkout_query_id     = null;
559
        $poll_id                   = null;
560
        $poll_answer_poll_id       = null;
561
        $my_chat_member_updated_id = null;
562
        $chat_member_updated_id    = null;
563
        $chat_join_request_id      = null;
564
565
        if (($message = $update->getMessage()) && self::insertMessageRequest($message)) {
566
            $chat_id    = $message->getChat()->getId();
567
            $message_id = $message->getMessageId();
568
        } elseif (($edited_message = $update->getEditedMessage()) && self::insertEditedMessageRequest($edited_message)) {
569
            $chat_id           = $edited_message->getChat()->getId();
570
            $edited_message_id = (int) self::$pdo->lastInsertId();
571
        } elseif (($channel_post = $update->getChannelPost()) && self::insertMessageRequest($channel_post)) {
572
            $chat_id         = $channel_post->getChat()->getId();
573
            $channel_post_id = $channel_post->getMessageId();
574
        } elseif (($edited_channel_post = $update->getEditedChannelPost()) && self::insertEditedMessageRequest($edited_channel_post)) {
575
            $chat_id                = $edited_channel_post->getChat()->getId();
576
            $edited_channel_post_id = (int) self::$pdo->lastInsertId();
577
        } elseif (($message_reaction = $update->getMessageReaction()) && self::insertMessageReaction($message_reaction)) {
578
            $chat_id             = $message_reaction->getChat()->getId();
579
            $message_id          = $message_reaction->getMessageId();
580
            $message_reaction_id = self::$pdo->lastInsertId();
581
        } elseif (($message_reaction_count = $update->getMessageReactionCount()) && self::insertMessageReactionCount($message_reaction_count)) {
582
            $chat_id                   = $message_reaction_count->getChat()->getId();
583
            $message_id                = $message_reaction_count->getMessageId();
584
            $message_reaction_count_id = self::$pdo->lastInsertId();
585
        } elseif (($inline_query = $update->getInlineQuery()) && self::insertInlineQueryRequest($inline_query)) {
586
            $inline_query_id = $inline_query->getId();
587
        } elseif (($chosen_inline_result = $update->getChosenInlineResult()) && self::insertChosenInlineResultRequest($chosen_inline_result)) {
588
            $chosen_inline_result_id = self::$pdo->lastInsertId();
589
        } elseif (($callback_query = $update->getCallbackQuery()) && self::insertCallbackQueryRequest($callback_query)) {
590
            $callback_query_id = $callback_query->getId();
591
        } elseif (($shipping_query = $update->getShippingQuery()) && self::insertShippingQueryRequest($shipping_query)) {
592
            $shipping_query_id = $shipping_query->getId();
593
        } elseif (($pre_checkout_query = $update->getPreCheckoutQuery()) && self::insertPreCheckoutQueryRequest($pre_checkout_query)) {
594
            $pre_checkout_query_id = $pre_checkout_query->getId();
595
        } elseif (($poll = $update->getPoll()) && self::insertPollRequest($poll)) {
596
            $poll_id = $poll->getId();
597
        } elseif (($poll_answer = $update->getPollAnswer()) && self::insertPollAnswerRequest($poll_answer)) {
598
            $poll_answer_poll_id = $poll_answer->getPollId();
599
        } elseif (($my_chat_member = $update->getMyChatMember()) && self::insertChatMemberUpdatedRequest($my_chat_member)) {
600
            $my_chat_member_updated_id = self::$pdo->lastInsertId();
601
        } elseif (($chat_member = $update->getChatMember()) && self::insertChatMemberUpdatedRequest($chat_member)) {
602
            $chat_member_updated_id = self::$pdo->lastInsertId();
603
        } elseif (($chat_join_request = $update->getChatJoinRequest()) && self::insertChatJoinRequestRequest($chat_join_request)) {
604
            $chat_join_request_id = self::$pdo->lastInsertId();
605
        } else {
606
            return false;
607
        }
608
609
        return self::insertTelegramUpdate(
610
            $update->getUpdateId(),
611
            $chat_id,
612
            $message_id,
613
            $edited_message_id,
614
            $channel_post_id,
615
            $edited_channel_post_id,
616
            $message_reaction_id,
617
            $message_reaction_count_id,
618
            $inline_query_id,
619
            $chosen_inline_result_id,
620
            $callback_query_id,
621
            $shipping_query_id,
622
            $pre_checkout_query_id,
623
            $poll_id,
624
            $poll_answer_poll_id,
625
            $my_chat_member_updated_id,
626
            $chat_member_updated_id,
627
            $chat_join_request_id
628
        );
629
    }
630
631
    public static function insertMessageReaction(MessageReactionUpdated $message_reaction): bool
632
    {
633
        if (!self::isDbConnected()) {
634
            return false;
635
        }
636
637
        try {
638
            $sth = self::$pdo->prepare('
639
                INSERT IGNORE INTO `' . TB_MESSAGE_REACTION . '`
0 ignored issues
show
Bug introduced by
The constant Longman\TelegramBot\TB_MESSAGE_REACTION was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
640
                (`chat_id`, `message_id`, `user_id`, `actor_chat_id`, `old_reaction`, `new_reaction`, `created_at`)
641
                VALUES
642
                (:chat_id, :message_id, :user_id, :actor_chat_id, :old_reaction, :new_reaction, :created_at)
643
            ');
644
645
            $date          = self::getTimestamp($message_reaction->getDate());
646
            $chat_id       = null;
647
            $user_id       = null;
648
            $actor_chat_id = null;
649
650
            if ($chat = $message_reaction->getChat()) {
651
                $chat_id = $chat->getId();
652
                self::insertChat($chat, $date);
653
            }
654
            if ($user = $message_reaction->getUser()) {
655
                $user_id = $user->getId();
656
                self::insertUser($user, $date);
657
            }
658
            if ($actor_chat = $message_reaction->getActorChat()) {
659
                $actor_chat_id = $actor_chat->getId();
660
                self::insertChat($actor_chat, $date);
661
            }
662
663
            $sth->bindValue(':chat_id', $chat_id);
664
            $sth->bindValue(':message_id', $message_reaction->getMessageId());
665
            $sth->bindValue(':user_id', $user_id);
666
            $sth->bindValue(':actor_chat_id', $actor_chat_id);
667
            $sth->bindValue(':old_reaction', self::entitiesArrayToJson($message_reaction->getOldReaction() ?: []));
668
            $sth->bindValue(':new_reaction', self::entitiesArrayToJson($message_reaction->getNewReaction() ?: []));
669
            $sth->bindValue(':created_at', $date);
670
671
            return $sth->execute();
672
        } catch (PDOException $e) {
673
            throw new TelegramException($e->getMessage());
674
        }
675
    }
676
677
    public static function insertMessageReactionCount(MessageReactionCountUpdated $message_reaction_count): bool
678
    {
679
        if (!self::isDbConnected()) {
680
            return false;
681
        }
682
683
        try {
684
            $sth = self::$pdo->prepare('
685
                INSERT IGNORE INTO `' . TB_MESSAGE_REACTION_COUNT . '`
0 ignored issues
show
Bug introduced by
The constant Longman\TelegramBot\TB_MESSAGE_REACTION_COUNT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
686
                (`chat_id`, `message_id`, `reactions`, `created_at`)
687
                VALUES
688
                (:chat_id, :message_id, :reactions, :created_at)
689
            ');
690
691
            $date    = self::getTimestamp($message_reaction_count->getDate());
692
            $chat_id = null;
693
694
            if ($chat = $message_reaction->getChat()) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $message_reaction does not exist. Did you maybe mean $message_reaction_count?
Loading history...
695
                $chat_id = $chat->getId();
696
                self::insertChat($chat, $date);
697
            }
698
699
            $sth->bindValue(':chat_id', $chat_id);
700
            $sth->bindValue(':message_id', $message_reaction_count->getMessageId());
701
            $sth->bindValue(':reactions', $message_reaction_count->getReactions());
702
            $sth->bindValue(':created_at', $date);
703
704
            return $sth->execute();
705
        } catch (PDOException $e) {
706
            throw new TelegramException($e->getMessage());
707
        }
708
    }
709
710
    /**
711
     * Insert inline query request into database
712
     *
713
     * @param InlineQuery $inline_query
714
     *
715
     * @return bool If the insert was successful
716
     * @throws TelegramException
717
     */
718
    public static function insertInlineQueryRequest(InlineQuery $inline_query): bool
719
    {
720
        if (!self::isDbConnected()) {
721
            return false;
722
        }
723
724
        try {
725
            $sth = self::$pdo->prepare('
726
                INSERT IGNORE INTO `' . TB_INLINE_QUERY . '`
727
                (`id`, `user_id`, `location`, `query`, `offset`, `chat_type`, `created_at`)
728
                VALUES
729
                (:id, :user_id, :location, :query, :offset, :chat_type, :created_at)
730
            ');
731
732
            $date    = self::getTimestamp();
733
            $user_id = null;
734
735
            if ($user = $inline_query->getFrom()) {
736
                $user_id = $user->getId();
737
                self::insertUser($user, $date);
738
            }
739
740
            $sth->bindValue(':id', $inline_query->getId());
741
            $sth->bindValue(':user_id', $user_id);
742
            $sth->bindValue(':location', $inline_query->getLocation());
743
            $sth->bindValue(':query', $inline_query->getQuery());
744
            $sth->bindValue(':offset', $inline_query->getOffset());
745
            $sth->bindValue(':chat_type', $inline_query->getChatType());
746
            $sth->bindValue(':created_at', $date);
747
748
            return $sth->execute();
749
        } catch (PDOException $e) {
750
            throw new TelegramException($e->getMessage());
751
        }
752
    }
753
754
    /**
755
     * Insert chosen inline result request into database
756
     *
757
     * @param ChosenInlineResult $chosen_inline_result
758
     *
759
     * @return bool If the insert was successful
760
     * @throws TelegramException
761
     */
762
    public static function insertChosenInlineResultRequest(ChosenInlineResult $chosen_inline_result): bool
763
    {
764
        if (!self::isDbConnected()) {
765
            return false;
766
        }
767
768
        try {
769
            $sth = self::$pdo->prepare('
770
                INSERT INTO `' . TB_CHOSEN_INLINE_RESULT . '`
771
                (`result_id`, `user_id`, `location`, `inline_message_id`, `query`, `created_at`)
772
                VALUES
773
                (:result_id, :user_id, :location, :inline_message_id, :query, :created_at)
774
            ');
775
776
            $date    = self::getTimestamp();
777
            $user_id = null;
778
779
            if ($user = $chosen_inline_result->getFrom()) {
780
                $user_id = $user->getId();
781
                self::insertUser($user, $date);
782
            }
783
784
            $sth->bindValue(':result_id', $chosen_inline_result->getResultId());
785
            $sth->bindValue(':user_id', $user_id);
786
            $sth->bindValue(':location', $chosen_inline_result->getLocation());
787
            $sth->bindValue(':inline_message_id', $chosen_inline_result->getInlineMessageId());
788
            $sth->bindValue(':query', $chosen_inline_result->getQuery());
789
            $sth->bindValue(':created_at', $date);
790
791
            return $sth->execute();
792
        } catch (PDOException $e) {
793
            throw new TelegramException($e->getMessage());
794
        }
795
    }
796
797
    /**
798
     * Insert callback query request into database
799
     *
800
     * @param CallbackQuery $callback_query
801
     *
802
     * @return bool If the insert was successful
803
     * @throws TelegramException
804
     */
805
    public static function insertCallbackQueryRequest(CallbackQuery $callback_query): bool
806
    {
807
        if (!self::isDbConnected()) {
808
            return false;
809
        }
810
811
        try {
812
            $sth = self::$pdo->prepare('
813
                INSERT IGNORE INTO `' . TB_CALLBACK_QUERY . '`
814
                (`id`, `user_id`, `chat_id`, `message_id`, `inline_message_id`, `chat_instance`, `data`, `game_short_name`, `created_at`)
815
                VALUES
816
                (:id, :user_id, :chat_id, :message_id, :inline_message_id, :chat_instance, :data, :game_short_name, :created_at)
817
            ');
818
819
            $date    = self::getTimestamp();
820
            $user_id = null;
821
822
            if ($user = $callback_query->getFrom()) {
823
                $user_id = $user->getId();
824
                self::insertUser($user, $date);
825
            }
826
827
            $chat_id    = null;
828
            $message_id = null;
829
            if ($message = $callback_query->getMessage()) {
830
                $chat_id    = $message->getChat()->getId();
831
                $message_id = $message->getMessageId();
832
833
                $is_message = self::$pdo->query('
834
                    SELECT *
835
                    FROM `' . TB_MESSAGE . '`
836
                    WHERE `id` = ' . $message_id . '
837
                      AND `chat_id` = ' . $chat_id . '
838
                    LIMIT 1
839
                ')->rowCount();
840
841
                if ($is_message) {
842
                    self::insertEditedMessageRequest($message);
843
                } else {
844
                    self::insertMessageRequest($message);
845
                }
846
            }
847
848
            $sth->bindValue(':id', $callback_query->getId());
849
            $sth->bindValue(':user_id', $user_id);
850
            $sth->bindValue(':chat_id', $chat_id);
851
            $sth->bindValue(':message_id', $message_id);
852
            $sth->bindValue(':inline_message_id', $callback_query->getInlineMessageId());
853
            $sth->bindValue(':chat_instance', $callback_query->getChatInstance());
854
            $sth->bindValue(':data', $callback_query->getData());
855
            $sth->bindValue(':game_short_name', $callback_query->getGameShortName());
856
            $sth->bindValue(':created_at', $date);
857
858
            return $sth->execute();
859
        } catch (PDOException $e) {
860
            throw new TelegramException($e->getMessage());
861
        }
862
    }
863
864
    /**
865
     * Insert shipping query request into database
866
     *
867
     * @param ShippingQuery $shipping_query
868
     *
869
     * @return bool If the insert was successful
870
     * @throws TelegramException
871
     */
872
    public static function insertShippingQueryRequest(ShippingQuery $shipping_query): bool
873
    {
874
        if (!self::isDbConnected()) {
875
            return false;
876
        }
877
878
        try {
879
            $sth = self::$pdo->prepare('
880
                INSERT IGNORE INTO `' . TB_SHIPPING_QUERY . '`
881
                (`id`, `user_id`, `invoice_payload`, `shipping_address`, `created_at`)
882
                VALUES
883
                (:id, :user_id, :invoice_payload, :shipping_address, :created_at)
884
            ');
885
886
            $date    = self::getTimestamp();
887
            $user_id = null;
888
889
            if ($user = $shipping_query->getFrom()) {
890
                $user_id = $user->getId();
891
                self::insertUser($user, $date);
892
            }
893
894
            $sth->bindValue(':id', $shipping_query->getId());
895
            $sth->bindValue(':user_id', $user_id);
896
            $sth->bindValue(':invoice_payload', $shipping_query->getInvoicePayload());
897
            $sth->bindValue(':shipping_address', $shipping_query->getShippingAddress());
898
            $sth->bindValue(':created_at', $date);
899
900
            return $sth->execute();
901
        } catch (PDOException $e) {
902
            throw new TelegramException($e->getMessage());
903
        }
904
    }
905
906
    /**
907
     * Insert pre checkout query request into database
908
     *
909
     * @param PreCheckoutQuery $pre_checkout_query
910
     *
911
     * @return bool If the insert was successful
912
     * @throws TelegramException
913
     */
914
    public static function insertPreCheckoutQueryRequest(PreCheckoutQuery $pre_checkout_query): bool
915
    {
916
        if (!self::isDbConnected()) {
917
            return false;
918
        }
919
920
        try {
921
            $sth = self::$pdo->prepare('
922
                INSERT IGNORE INTO `' . TB_PRE_CHECKOUT_QUERY . '`
923
                (`id`, `user_id`, `currency`, `total_amount`, `invoice_payload`, `shipping_option_id`, `order_info`, `created_at`)
924
                VALUES
925
                (:id, :user_id, :currency, :total_amount, :invoice_payload, :shipping_option_id, :order_info, :created_at)
926
            ');
927
928
            $date    = self::getTimestamp();
929
            $user_id = null;
930
931
            if ($user = $pre_checkout_query->getFrom()) {
932
                $user_id = $user->getId();
933
                self::insertUser($user, $date);
934
            }
935
936
            $sth->bindValue(':id', $pre_checkout_query->getId());
937
            $sth->bindValue(':user_id', $user_id);
938
            $sth->bindValue(':currency', $pre_checkout_query->getCurrency());
939
            $sth->bindValue(':total_amount', $pre_checkout_query->getTotalAmount());
940
            $sth->bindValue(':invoice_payload', $pre_checkout_query->getInvoicePayload());
941
            $sth->bindValue(':shipping_option_id', $pre_checkout_query->getShippingOptionId());
942
            $sth->bindValue(':order_info', $pre_checkout_query->getOrderInfo());
943
            $sth->bindValue(':created_at', $date);
944
945
            return $sth->execute();
946
        } catch (PDOException $e) {
947
            throw new TelegramException($e->getMessage());
948
        }
949
    }
950
951
    /**
952
     * Insert poll request into database
953
     *
954
     * @param Poll $poll
955
     *
956
     * @return bool If the insert was successful
957
     * @throws TelegramException
958
     */
959
    public static function insertPollRequest(Poll $poll): bool
960
    {
961
        if (!self::isDbConnected()) {
962
            return false;
963
        }
964
965
        try {
966
            $sth = self::$pdo->prepare('
967
                INSERT INTO `' . TB_POLL . '`
968
                (`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`)
969
                VALUES
970
                (: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)
971
                ON DUPLICATE KEY UPDATE
972
                    `options`                 = VALUES(`options`),
973
                    `total_voter_count`       = VALUES(`total_voter_count`),
974
                    `is_closed`               = VALUES(`is_closed`),
975
                    `is_anonymous`            = VALUES(`is_anonymous`),
976
                    `type`                    = VALUES(`type`),
977
                    `allows_multiple_answers` = VALUES(`allows_multiple_answers`),
978
                    `correct_option_id`       = VALUES(`correct_option_id`),
979
                    `explanation`             = VALUES(`explanation`),
980
                    `explanation_entities`    = VALUES(`explanation_entities`),
981
                    `open_period`             = VALUES(`open_period`),
982
                    `close_date`              = VALUES(`close_date`)
983
            ');
984
985
            $sth->bindValue(':id', $poll->getId());
986
            $sth->bindValue(':question', $poll->getQuestion());
987
            $sth->bindValue(':options', self::entitiesArrayToJson($poll->getOptions() ?: []));
988
            $sth->bindValue(':total_voter_count', $poll->getTotalVoterCount());
989
            $sth->bindValue(':is_closed', $poll->getIsClosed(), PDO::PARAM_INT);
990
            $sth->bindValue(':is_anonymous', $poll->getIsAnonymous(), PDO::PARAM_INT);
991
            $sth->bindValue(':type', $poll->getType());
992
            $sth->bindValue(':allows_multiple_answers', $poll->getAllowsMultipleAnswers(), PDO::PARAM_INT);
993
            $sth->bindValue(':correct_option_id', $poll->getCorrectOptionId());
994
            $sth->bindValue(':explanation', $poll->getExplanation());
995
            $sth->bindValue(':explanation_entities', self::entitiesArrayToJson($poll->getExplanationEntities() ?: []));
996
            $sth->bindValue(':open_period', $poll->getOpenPeriod());
997
            $sth->bindValue(':close_date', self::getTimestamp($poll->getCloseDate()));
998
            $sth->bindValue(':created_at', self::getTimestamp());
999
1000
            return $sth->execute();
1001
        } catch (PDOException $e) {
1002
            throw new TelegramException($e->getMessage());
1003
        }
1004
    }
1005
1006
    /**
1007
     * Insert poll answer request into database
1008
     *
1009
     * @param PollAnswer $poll_answer
1010
     *
1011
     * @return bool If the insert was successful
1012
     * @throws TelegramException
1013
     */
1014
    public static function insertPollAnswerRequest(PollAnswer $poll_answer): bool
1015
    {
1016
        if (!self::isDbConnected()) {
1017
            return false;
1018
        }
1019
1020
        try {
1021
            $sth = self::$pdo->prepare('
1022
                INSERT INTO `' . TB_POLL_ANSWER . '`
1023
                (`poll_id`, `user_id`, `option_ids`, `created_at`)
1024
                VALUES
1025
                (:poll_id, :user_id, :option_ids, :created_at)
1026
                ON DUPLICATE KEY UPDATE
1027
                    `option_ids` = VALUES(`option_ids`)
1028
            ');
1029
1030
            $date    = self::getTimestamp();
1031
            $user_id = null;
1032
1033
            if ($user = $poll_answer->getUser()) {
1034
                $user_id = $user->getId();
1035
                self::insertUser($user, $date);
1036
            }
1037
1038
            $sth->bindValue(':poll_id', $poll_answer->getPollId());
1039
            $sth->bindValue(':user_id', $user_id);
1040
            $sth->bindValue(':option_ids', json_encode($poll_answer->getOptionIds()));
1041
            $sth->bindValue(':created_at', $date);
1042
1043
            return $sth->execute();
1044
        } catch (PDOException $e) {
1045
            throw new TelegramException($e->getMessage());
1046
        }
1047
    }
1048
1049
    /**
1050
     * Insert chat member updated request into database
1051
     *
1052
     * @param ChatMemberUpdated $chat_member_updated
1053
     *
1054
     * @return bool If the insert was successful
1055
     * @throws TelegramException
1056
     */
1057
    public static function insertChatMemberUpdatedRequest(ChatMemberUpdated $chat_member_updated): bool
1058
    {
1059
        if (!self::isDbConnected()) {
1060
            return false;
1061
        }
1062
1063
        try {
1064
            $sth = self::$pdo->prepare('
1065
                INSERT INTO `' . TB_CHAT_MEMBER_UPDATED . '`
0 ignored issues
show
Bug introduced by
The constant Longman\TelegramBot\TB_CHAT_MEMBER_UPDATED was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1066
                (`chat_id`, `user_id`, `date`, `old_chat_member`, `new_chat_member`, `invite_link`, `created_at`)
1067
                VALUES
1068
                (:chat_id, :user_id, :date, :old_chat_member, :new_chat_member, :invite_link, :created_at)
1069
            ');
1070
1071
            $date    = self::getTimestamp();
1072
            $chat_id = null;
1073
            $user_id = null;
1074
1075
            if ($chat = $chat_member_updated->getChat()) {
1076
                $chat_id = $chat->getId();
1077
                self::insertChat($chat, $date);
1078
            }
1079
            if ($user = $chat_member_updated->getFrom()) {
1080
                $user_id = $user->getId();
1081
                self::insertUser($user, $date);
1082
            }
1083
1084
            $sth->bindValue(':chat_id', $chat_id);
1085
            $sth->bindValue(':user_id', $user_id);
1086
            $sth->bindValue(':date', self::getTimestamp($chat_member_updated->getDate()));
1087
            $sth->bindValue(':old_chat_member', $chat_member_updated->getOldChatMember());
1088
            $sth->bindValue(':new_chat_member', $chat_member_updated->getNewChatMember());
1089
            $sth->bindValue(':invite_link', $chat_member_updated->getInviteLink());
1090
            $sth->bindValue(':created_at', $date);
1091
1092
            return $sth->execute();
1093
        } catch (PDOException $e) {
1094
            throw new TelegramException($e->getMessage());
1095
        }
1096
    }
1097
1098
    /**
1099
     * Insert chat join request into database
1100
     *
1101
     * @param ChatJoinRequest $chat_join_request
1102
     *
1103
     * @return bool If the insert was successful
1104
     * @throws TelegramException
1105
     */
1106
    public static function insertChatJoinRequestRequest(ChatJoinRequest $chat_join_request): bool
1107
    {
1108
        if (!self::isDbConnected()) {
1109
            return false;
1110
        }
1111
1112
        try {
1113
            $sth = self::$pdo->prepare('
1114
                INSERT INTO `' . TB_CHAT_JOIN_REQUEST . '`
0 ignored issues
show
Bug introduced by
The constant Longman\TelegramBot\TB_CHAT_JOIN_REQUEST was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1115
                (`chat_id`, `user_id`, `date`, `bio`, `invite_link`, `created_at`)
1116
                VALUES
1117
                (:chat_id, :user_id, :date, :bio, :invite_link, :created_at)
1118
            ');
1119
1120
            $date    = self::getTimestamp();
1121
            $chat_id = null;
1122
            $user_id = null;
1123
1124
            if ($chat = $chat_join_request->getChat()) {
1125
                $chat_id = $chat->getId();
1126
                self::insertChat($chat, $date);
1127
            }
1128
            if ($user = $chat_join_request->getFrom()) {
1129
                $user_id = $user->getId();
1130
                self::insertUser($user, $date);
1131
            }
1132
1133
            $sth->bindValue(':chat_id', $chat_id);
1134
            $sth->bindValue(':user_id', $user_id);
1135
            $sth->bindValue(':date', self::getTimestamp($chat_join_request->getDate()));
1136
            $sth->bindValue(':bio', $chat_join_request->getBio());
1137
            $sth->bindValue(':invite_link', $chat_join_request->getInviteLink());
1138
            $sth->bindValue(':created_at', $date);
1139
1140
            return $sth->execute();
1141
        } catch (PDOException $e) {
1142
            throw new TelegramException($e->getMessage());
1143
        }
1144
    }
1145
1146
    /**
1147
     * Insert Message request in db
1148
     *
1149
     * @param Message $message
1150
     *
1151
     * @return bool If the insert was successful
1152
     * @throws TelegramException
1153
     */
1154
    public static function insertMessageRequest(Message $message): bool
1155
    {
1156
        if (!self::isDbConnected()) {
1157
            return false;
1158
        }
1159
1160
        $date = self::getTimestamp($message->getDate());
1161
1162
        // Insert chat, update chat id in case it migrated
1163
        $chat = $message->getChat();
1164
        self::insertChat($chat, $date, $message->getMigrateToChatId());
1165
1166
        $sender_chat_id = null;
1167
        if ($sender_chat = $message->getSenderChat()) {
1168
            self::insertChat($sender_chat);
1169
            $sender_chat_id = $sender_chat->getId();
1170
        }
1171
1172
        // Insert user and the relation with the chat
1173
        if ($user = $message->getFrom()) {
1174
            self::insertUser($user, $date, $chat);
1175
        }
1176
1177
        // Insert the forwarded message user in users table
1178
        $forward_date = $message->getForwardDate() ? self::getTimestamp($message->getForwardDate()) : null;
1179
1180
        if ($forward_from = $message->getForwardFrom()) {
1181
            self::insertUser($forward_from);
1182
            $forward_from = $forward_from->getId();
1183
        }
1184
        if ($forward_from_chat = $message->getForwardFromChat()) {
1185
            self::insertChat($forward_from_chat);
1186
            $forward_from_chat = $forward_from_chat->getId();
1187
        }
1188
1189
        $via_bot_id = null;
1190
        if ($via_bot = $message->getViaBot()) {
1191
            self::insertUser($via_bot);
1192
            $via_bot_id = $via_bot->getId();
1193
        }
1194
1195
        // New and left chat member
1196
        $new_chat_members_ids = null;
1197
        $left_chat_member_id  = null;
1198
1199
        $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

1199
        /** @scrutinizer ignore-call */ 
1200
        $new_chat_members = $message->getNewChatMembers();
Loading history...
1200
        $left_chat_member = $message->getLeftChatMember();
1201
        if (!empty($new_chat_members)) {
1202
            foreach ($new_chat_members as $new_chat_member) {
1203
                if ($new_chat_member instanceof User) {
1204
                    // Insert the new chat user
1205
                    self::insertUser($new_chat_member, $date, $chat);
1206
                    $new_chat_members_ids[] = $new_chat_member->getId();
1207
                }
1208
            }
1209
            $new_chat_members_ids = implode(',', $new_chat_members_ids);
1210
        } 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...
1211
            // Insert the left chat user
1212
            self::insertUser($left_chat_member, $date, $chat);
1213
            $left_chat_member_id = $left_chat_member->getId();
1214
        }
1215
1216
        try {
1217
            $sth = self::$pdo->prepare('
1218
                INSERT IGNORE INTO `' . TB_MESSAGE . '`
1219
                (
1220
                    `id`, `user_id`, `chat_id`, `message_thread_id`, `sender_chat_id`, `date`, `forward_from`, `forward_from_chat`, `forward_from_message_id`,
1221
                    `forward_signature`, `forward_sender_name`, `forward_date`, `is_topic_message`,
1222
                    `reply_to_chat`, `reply_to_message`, `via_bot`, `edit_date`, `media_group_id`, `author_signature`, `text`, `entities`, `caption_entities`,
1223
                    `audio`, `document`, `animation`, `game`, `photo`, `sticker`, `story`, `video`, `voice`, `video_note`, `caption`, `has_media_spoiler`, `contact`,
1224
                    `location`, `venue`, `poll`, `dice`, `new_chat_members`, `left_chat_member`,
1225
                    `new_chat_title`, `new_chat_photo`, `delete_chat_photo`, `group_chat_created`,
1226
                    `supergroup_chat_created`, `channel_chat_created`, `message_auto_delete_timer_changed`, `migrate_to_chat_id`, `migrate_from_chat_id`,
1227
                    `pinned_message`, `invoice`, `successful_payment`, `user_shared`, `chat_shared`, `connected_website`, `write_access_allowed`, `passport_data`, `proximity_alert_triggered`,
1228
                    `forum_topic_created`, `forum_topic_edited`, `forum_topic_closed`, `forum_topic_reopened`, `general_forum_topic_hidden`, `general_forum_topic_unhidden`,
1229
                    `video_chat_scheduled`, `video_chat_started`, `video_chat_ended`, `video_chat_participants_invited`, `web_app_data`, `reply_markup`
1230
                ) VALUES (
1231
                    :message_id, :user_id, :chat_id, :message_thread_id, :sender_chat_id, :date, :forward_from, :forward_from_chat, :forward_from_message_id,
1232
                    :forward_signature, :forward_sender_name, :forward_date, :is_topic_message,
1233
                    :reply_to_chat, :reply_to_message, :via_bot, :edit_date, :media_group_id, :author_signature, :text, :entities, :caption_entities,
1234
                    :audio, :document, :animation, :game, :photo, :sticker, :story, :video, :voice, :video_note, :caption, :has_media_spoiler, :contact,
1235
                    :location, :venue, :poll, :dice, :new_chat_members, :left_chat_member,
1236
                    :new_chat_title, :new_chat_photo, :delete_chat_photo, :group_chat_created,
1237
                    :supergroup_chat_created, :channel_chat_created, :message_auto_delete_timer_changed, :migrate_to_chat_id, :migrate_from_chat_id,
1238
                    :pinned_message, :invoice, :successful_payment, :user_shared, :chat_shared, :connected_website, :write_access_allowed, :passport_data, :proximity_alert_triggered,
1239
                    :forum_topic_created, :forum_topic_edited, :forum_topic_closed, :forum_topic_reopened, :general_forum_topic_hidden, :general_forum_topic_unhidden,
1240
                    :video_chat_scheduled, :video_chat_started, :video_chat_ended, :video_chat_participants_invited, :web_app_data, :reply_markup
1241
                )
1242
            ');
1243
1244
            $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...
1245
            $chat_id = $chat->getId();
1246
1247
            $reply_to_message_id = null;
1248
            if ($reply_to_message = $message->getReplyToMessage()) {
1249
                $reply_to_message_id = $reply_to_message->getMessageId();
1250
                // please notice that, as explained in the documentation, reply_to_message don't contain other
1251
                // reply_to_message field so recursion deep is 1
1252
                self::insertMessageRequest($reply_to_message);
1253
            }
1254
1255
            $sth->bindValue(':message_id', $message->getMessageId());
1256
            $sth->bindValue(':chat_id', $chat_id);
1257
            $sth->bindValue(':sender_chat_id', $sender_chat_id);
1258
            $sth->bindValue(':message_thread_id', $message->getMessageThreadId());
1259
            $sth->bindValue(':user_id', $user_id);
1260
            $sth->bindValue(':date', $date);
1261
            $sth->bindValue(':forward_from', $forward_from);
1262
            $sth->bindValue(':forward_from_chat', $forward_from_chat);
1263
            $sth->bindValue(':forward_from_message_id', $message->getForwardFromMessageId());
1264
            $sth->bindValue(':forward_signature', $message->getForwardSignature());
1265
            $sth->bindValue(':forward_sender_name', $message->getForwardSenderName());
1266
            $sth->bindValue(':forward_date', $forward_date);
1267
            $sth->bindValue(':is_topic_message', $message->getIsTopicMessage());
1268
1269
            $reply_to_chat_id = null;
1270
            if ($reply_to_message_id !== null) {
1271
                $reply_to_chat_id = $chat_id;
1272
            }
1273
            $sth->bindValue(':reply_to_chat', $reply_to_chat_id);
1274
            $sth->bindValue(':reply_to_message', $reply_to_message_id);
1275
1276
            $sth->bindValue(':via_bot', $via_bot_id);
1277
            $sth->bindValue(':edit_date', self::getTimestamp($message->getEditDate()));
1278
            $sth->bindValue(':media_group_id', $message->getMediaGroupId());
1279
            $sth->bindValue(':author_signature', $message->getAuthorSignature());
1280
            $sth->bindValue(':text', $message->getText());
1281
            $sth->bindValue(':entities', self::entitiesArrayToJson($message->getEntities() ?: []));
1282
            $sth->bindValue(':caption_entities', self::entitiesArrayToJson($message->getCaptionEntities() ?: []));
1283
            $sth->bindValue(':audio', $message->getAudio());
1284
            $sth->bindValue(':document', $message->getDocument());
1285
            $sth->bindValue(':animation', $message->getAnimation());
1286
            $sth->bindValue(':game', $message->getGame());
1287
            $sth->bindValue(':photo', self::entitiesArrayToJson($message->getPhoto() ?: []));
1288
            $sth->bindValue(':sticker', $message->getSticker());
1289
            $sth->bindValue(':story', $message->getStory());
1290
            $sth->bindValue(':video', $message->getVideo());
1291
            $sth->bindValue(':voice', $message->getVoice());
1292
            $sth->bindValue(':video_note', $message->getVideoNote());
1293
            $sth->bindValue(':caption', $message->getCaption());
1294
            $sth->bindValue(':has_media_spoiler', $message->getHasMediaSpoiler());
1295
            $sth->bindValue(':contact', $message->getContact());
1296
            $sth->bindValue(':location', $message->getLocation());
1297
            $sth->bindValue(':venue', $message->getVenue());
1298
            $sth->bindValue(':poll', $message->getPoll());
1299
            $sth->bindValue(':dice', $message->getDice());
1300
            $sth->bindValue(':new_chat_members', $new_chat_members_ids);
1301
            $sth->bindValue(':left_chat_member', $left_chat_member_id);
1302
            $sth->bindValue(':new_chat_title', $message->getNewChatTitle());
1303
            $sth->bindValue(':new_chat_photo', self::entitiesArrayToJson($message->getNewChatPhoto() ?: []));
1304
            $sth->bindValue(':delete_chat_photo', $message->getDeleteChatPhoto());
1305
            $sth->bindValue(':group_chat_created', $message->getGroupChatCreated());
1306
            $sth->bindValue(':supergroup_chat_created', $message->getSupergroupChatCreated());
1307
            $sth->bindValue(':channel_chat_created', $message->getChannelChatCreated());
1308
            $sth->bindValue(':message_auto_delete_timer_changed', $message->getMessageAutoDeleteTimerChanged());
1309
            $sth->bindValue(':migrate_to_chat_id', $message->getMigrateToChatId());
1310
            $sth->bindValue(':migrate_from_chat_id', $message->getMigrateFromChatId());
1311
            $sth->bindValue(':pinned_message', $message->getPinnedMessage());
1312
            $sth->bindValue(':invoice', $message->getInvoice());
1313
            $sth->bindValue(':successful_payment', $message->getSuccessfulPayment());
1314
            $sth->bindValue(':user_shared', $message->getUserShared());
1315
            $sth->bindValue(':chat_shared', $message->getChatShared());
1316
            $sth->bindValue(':connected_website', $message->getConnectedWebsite());
1317
            $sth->bindValue(':write_access_allowed', $message->getWriteAccessAllowed());
1318
            $sth->bindValue(':passport_data', $message->getPassportData());
1319
            $sth->bindValue(':proximity_alert_triggered', $message->getProximityAlertTriggered());
1320
            $sth->bindValue(':forum_topic_created', $message->getForumTopicCreated());
1321
            $sth->bindValue(':forum_topic_edited', $message->getForumTopicEdited());
1322
            $sth->bindValue(':forum_topic_closed', $message->getForumTopicClosed());
1323
            $sth->bindValue(':forum_topic_reopened', $message->getForumTopicReopened());
1324
            $sth->bindValue(':general_forum_topic_hidden', $message->getGeneralForumTopicHidden());
1325
            $sth->bindValue(':general_forum_topic_unhidden', $message->getGeneralForumTopicUnhidden());
1326
            $sth->bindValue(':video_chat_scheduled', $message->getVideoChatScheduled());
1327
            $sth->bindValue(':video_chat_started', $message->getVideoChatStarted());
1328
            $sth->bindValue(':video_chat_ended', $message->getVideoChatEnded());
1329
            $sth->bindValue(':video_chat_participants_invited', $message->getVideoChatParticipantsInvited());
1330
            $sth->bindValue(':web_app_data', $message->getWebAppData());
1331
            $sth->bindValue(':reply_markup', $message->getReplyMarkup());
1332
1333
            return $sth->execute();
1334
        } catch (PDOException $e) {
1335
            throw new TelegramException($e->getMessage());
1336
        }
1337
    }
1338
1339
    /**
1340
     * Insert Edited Message request in db
1341
     *
1342
     * @param Message $edited_message
1343
     *
1344
     * @return bool If the insert was successful
1345
     * @throws TelegramException
1346
     */
1347
    public static function insertEditedMessageRequest(Message $edited_message): bool
1348
    {
1349
        if (!self::isDbConnected()) {
1350
            return false;
1351
        }
1352
1353
        try {
1354
            $edit_date = self::getTimestamp($edited_message->getEditDate());
1355
1356
            // Insert chat
1357
            $chat = $edited_message->getChat();
1358
            self::insertChat($chat, $edit_date);
1359
1360
            // Insert user and the relation with the chat
1361
            if ($user = $edited_message->getFrom()) {
1362
                self::insertUser($user, $edit_date, $chat);
1363
            }
1364
1365
            $sth = self::$pdo->prepare('
1366
                INSERT IGNORE INTO `' . TB_EDITED_MESSAGE . '`
1367
                (`chat_id`, `message_id`, `user_id`, `edit_date`, `text`, `entities`, `caption`)
1368
                VALUES
1369
                (:chat_id, :message_id, :user_id, :edit_date, :text, :entities, :caption)
1370
            ');
1371
1372
            $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...
1373
1374
            $sth->bindValue(':chat_id', $chat->getId());
1375
            $sth->bindValue(':message_id', $edited_message->getMessageId());
1376
            $sth->bindValue(':user_id', $user_id);
1377
            $sth->bindValue(':edit_date', $edit_date);
1378
            $sth->bindValue(':text', $edited_message->getText());
1379
            $sth->bindValue(':entities', self::entitiesArrayToJson($edited_message->getEntities() ?: []));
1380
            $sth->bindValue(':caption', $edited_message->getCaption());
1381
1382
            return $sth->execute();
1383
        } catch (PDOException $e) {
1384
            throw new TelegramException($e->getMessage());
1385
        }
1386
    }
1387
1388
    /**
1389
     * Select Groups, Supergroups, Channels and/or single user Chats (also by ID or text)
1390
     *
1391
     * @param $select_chats_params
1392
     *
1393
     * @return array|bool
1394
     * @throws TelegramException
1395
     */
1396
    public static function selectChats($select_chats_params)
1397
    {
1398
        if (!self::isDbConnected()) {
1399
            return false;
1400
        }
1401
1402
        // Set defaults for omitted values.
1403
        $select = array_merge([
1404
            'groups'      => true,
1405
            'supergroups' => true,
1406
            'channels'    => true,
1407
            'users'       => true,
1408
            'date_from'   => null,
1409
            'date_to'     => null,
1410
            'chat_id'     => null,
1411
            'text'        => null,
1412
            'language'    => null,
1413
        ], $select_chats_params);
1414
1415
        if (!$select['groups'] && !$select['users'] && !$select['supergroups'] && !$select['channels']) {
1416
            return false;
1417
        }
1418
1419
        try {
1420
            $query = '
1421
                SELECT * ,
1422
                ' . TB_CHAT . '.`id` AS `chat_id`,
1423
                ' . TB_CHAT . '.`username` AS `chat_username`,
1424
                ' . TB_CHAT . '.`created_at` AS `chat_created_at`,
1425
                ' . TB_CHAT . '.`updated_at` AS `chat_updated_at`
1426
            ';
1427
            if ($select['users']) {
1428
                $query .= '
1429
                    , ' . TB_USER . '.`id` AS `user_id`
1430
                    FROM `' . TB_CHAT . '`
1431
                    LEFT JOIN `' . TB_USER . '`
1432
                    ON ' . TB_CHAT . '.`id`=' . TB_USER . '.`id`
1433
                ';
1434
            } else {
1435
                $query .= 'FROM `' . TB_CHAT . '`';
1436
            }
1437
1438
            // Building parts of query
1439
            $where  = [];
1440
            $tokens = [];
1441
1442
            if (!$select['groups'] || !$select['users'] || !$select['supergroups'] || !$select['channels']) {
1443
                $chat_or_user = [];
1444
1445
                $select['groups'] && $chat_or_user[] = TB_CHAT . '.`type` = "group"';
1446
                $select['supergroups'] && $chat_or_user[] = TB_CHAT . '.`type` = "supergroup"';
1447
                $select['channels'] && $chat_or_user[] = TB_CHAT . '.`type` = "channel"';
1448
                $select['users'] && $chat_or_user[] = TB_CHAT . '.`type` = "private"';
1449
1450
                $where[] = '(' . implode(' OR ', $chat_or_user) . ')';
1451
            }
1452
1453
            if (null !== $select['date_from']) {
1454
                $where[]              = TB_CHAT . '.`updated_at` >= :date_from';
1455
                $tokens[':date_from'] = $select['date_from'];
1456
            }
1457
1458
            if (null !== $select['date_to']) {
1459
                $where[]            = TB_CHAT . '.`updated_at` <= :date_to';
1460
                $tokens[':date_to'] = $select['date_to'];
1461
            }
1462
1463
            if (null !== $select['chat_id']) {
1464
                $where[]            = TB_CHAT . '.`id` = :chat_id';
1465
                $tokens[':chat_id'] = $select['chat_id'];
1466
            }
1467
1468
            if ($select['users'] && null !== $select['language']) {
1469
                $where[]             = TB_USER . '.`language_code` = :language';
1470
                $tokens[':language'] = $select['language'];
1471
            }
1472
1473
            if (null !== $select['text']) {
1474
                $text_like = '%' . strtolower($select['text']) . '%';
1475
                if ($select['users']) {
1476
                    $where[]          = '(
1477
                        LOWER(' . TB_CHAT . '.`title`) LIKE :text1
1478
                        OR LOWER(' . TB_USER . '.`first_name`) LIKE :text2
1479
                        OR LOWER(' . TB_USER . '.`last_name`) LIKE :text3
1480
                        OR LOWER(' . TB_USER . '.`username`) LIKE :text4
1481
                    )';
1482
                    $tokens[':text1'] = $text_like;
1483
                    $tokens[':text2'] = $text_like;
1484
                    $tokens[':text3'] = $text_like;
1485
                    $tokens[':text4'] = $text_like;
1486
                } else {
1487
                    $where[]         = 'LOWER(' . TB_CHAT . '.`title`) LIKE :text';
1488
                    $tokens[':text'] = $text_like;
1489
                }
1490
            }
1491
1492
            if (!empty($where)) {
1493
                $query .= ' WHERE ' . implode(' AND ', $where);
1494
            }
1495
1496
            $query .= ' ORDER BY ' . TB_CHAT . '.`updated_at` ASC';
1497
1498
            $sth = self::$pdo->prepare($query);
1499
            $sth->execute($tokens);
1500
1501
            return $sth->fetchAll(PDO::FETCH_ASSOC);
1502
        } catch (PDOException $e) {
1503
            throw new TelegramException($e->getMessage());
1504
        }
1505
    }
1506
1507
    /**
1508
     * Get Telegram API request count for current chat / message
1509
     *
1510
     * @param int|string|null $chat_id
1511
     * @param string|null     $inline_message_id
1512
     *
1513
     * @return array|bool Array containing TOTAL and CURRENT fields or false on invalid arguments
1514
     * @throws TelegramException
1515
     */
1516
    public static function getTelegramRequestCount($chat_id = null, string $inline_message_id = null)
1517
    {
1518
        if (!self::isDbConnected()) {
1519
            return false;
1520
        }
1521
1522
        try {
1523
            $sth = self::$pdo->prepare('SELECT
1524
                (SELECT COUNT(DISTINCT `chat_id`) FROM `' . TB_REQUEST_LIMITER . '` WHERE `created_at` >= :created_at_1) AS LIMIT_PER_SEC_ALL,
1525
                (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,
1526
                (SELECT COUNT(*) FROM `' . TB_REQUEST_LIMITER . '` WHERE `created_at` >= :created_at_minute AND `chat_id` = :chat_id_2) AS LIMIT_PER_MINUTE
1527
            ');
1528
1529
            $date        = self::getTimestamp();
1530
            $date_minute = self::getTimestamp(strtotime('-1 minute'));
1531
1532
            $sth->bindValue(':chat_id_1', $chat_id);
1533
            $sth->bindValue(':chat_id_2', $chat_id);
1534
            $sth->bindValue(':inline_message_id', $inline_message_id);
1535
            $sth->bindValue(':created_at_1', $date);
1536
            $sth->bindValue(':created_at_2', $date);
1537
            $sth->bindValue(':created_at_minute', $date_minute);
1538
1539
            $sth->execute();
1540
1541
            return $sth->fetch();
1542
        } catch (PDOException $e) {
1543
            throw new TelegramException($e->getMessage());
1544
        }
1545
    }
1546
1547
    /**
1548
     * Insert Telegram API request in db
1549
     *
1550
     * @param string $method
1551
     * @param array  $data
1552
     *
1553
     * @return bool If the insert was successful
1554
     * @throws TelegramException
1555
     */
1556
    public static function insertTelegramRequest(string $method, array $data): bool
1557
    {
1558
        if (!self::isDbConnected()) {
1559
            return false;
1560
        }
1561
1562
        try {
1563
            $sth = self::$pdo->prepare('INSERT INTO `' . TB_REQUEST_LIMITER . '`
1564
                (`method`, `chat_id`, `inline_message_id`, `created_at`)
1565
                VALUES
1566
                (:method, :chat_id, :inline_message_id, :created_at);
1567
            ');
1568
1569
            $chat_id           = $data['chat_id'] ?? null;
1570
            $inline_message_id = $data['inline_message_id'] ?? null;
1571
1572
            $sth->bindValue(':chat_id', $chat_id);
1573
            $sth->bindValue(':inline_message_id', $inline_message_id);
1574
            $sth->bindValue(':method', $method);
1575
            $sth->bindValue(':created_at', self::getTimestamp());
1576
1577
            return $sth->execute();
1578
        } catch (PDOException $e) {
1579
            throw new TelegramException($e->getMessage());
1580
        }
1581
    }
1582
1583
    /**
1584
     * Bulk update the entries of any table
1585
     *
1586
     * @param string $table
1587
     * @param array  $fields_values
1588
     * @param array  $where_fields_values
1589
     *
1590
     * @return bool
1591
     * @throws TelegramException
1592
     */
1593
    public static function update(string $table, array $fields_values, array $where_fields_values): bool
1594
    {
1595
        if (empty($fields_values) || !self::isDbConnected()) {
1596
            return false;
1597
        }
1598
1599
        try {
1600
            // Building parts of query
1601
            $tokens = $fields = $where = [];
1602
1603
            // Fields with values to update
1604
            foreach ($fields_values as $field => $value) {
1605
                $token          = ':' . count($tokens);
1606
                $fields[]       = "`{$field}` = {$token}";
1607
                $tokens[$token] = $value;
1608
            }
1609
1610
            // Where conditions
1611
            foreach ($where_fields_values as $field => $value) {
1612
                $token          = ':' . count($tokens);
1613
                $where[]        = "`{$field}` = {$token}";
1614
                $tokens[$token] = $value;
1615
            }
1616
1617
            $sql = 'UPDATE `' . $table . '` SET ' . implode(', ', $fields);
1618
            $sql .= count($where) > 0 ? ' WHERE ' . implode(' AND ', $where) : '';
1619
1620
            return self::$pdo->prepare($sql)->execute($tokens);
1621
        } catch (PDOException $e) {
1622
            throw new TelegramException($e->getMessage());
1623
        }
1624
    }
1625
}
1626