Completed
Pull Request — develop (#958)
by Armando
03:20
created

DB::runMigrations()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 40

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

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

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
587
    {
588
        if (!self::isDbConnected()) {
589
            return false;
590
        }
591
592
        try {
593
            $sth = self::$pdo->prepare('
594
                INSERT IGNORE INTO `' . TB_INLINE_QUERY . '`
595
                (`id`, `user_id`, `location`, `query`, `offset`, `created_at`)
596
                VALUES
597
                (:id, :user_id, :location, :query, :offset, :created_at)
598
            ');
599
600
            $date    = self::getTimestamp();
601
            $user_id = null;
602
603
            $user = $inline_query->getFrom();
604
            if ($user instanceof User) {
605
                $user_id = $user->getId();
606
                self::insertUser($user, $date);
607
            }
608
609
            $sth->bindValue(':id', $inline_query->getId());
610
            $sth->bindValue(':user_id', $user_id);
611
            $sth->bindValue(':location', $inline_query->getLocation());
612
            $sth->bindValue(':query', $inline_query->getQuery());
613
            $sth->bindValue(':offset', $inline_query->getOffset());
614
            $sth->bindValue(':created_at', $date);
615
616
            return $sth->execute();
617
        } catch (PDOException $e) {
618
            throw new TelegramException($e->getMessage());
619
        }
620
    }
621
622
    /**
623
     * Insert chosen inline result request into database
624
     *
625
     * @param ChosenInlineResult $chosen_inline_result
626
     *
627
     * @return bool If the insert was successful
628
     * @throws TelegramException
629
     */
630 View Code Duplication
    public static function insertChosenInlineResultRequest(ChosenInlineResult $chosen_inline_result)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
631
    {
632
        if (!self::isDbConnected()) {
633
            return false;
634
        }
635
636
        try {
637
            $sth = self::$pdo->prepare('
638
                INSERT INTO `' . TB_CHOSEN_INLINE_RESULT . '`
639
                (`result_id`, `user_id`, `location`, `inline_message_id`, `query`, `created_at`)
640
                VALUES
641
                (:result_id, :user_id, :location, :inline_message_id, :query, :created_at)
642
            ');
643
644
            $date    = self::getTimestamp();
645
            $user_id = null;
646
647
            $user = $chosen_inline_result->getFrom();
648
            if ($user instanceof User) {
649
                $user_id = $user->getId();
650
                self::insertUser($user, $date);
651
            }
652
653
            $sth->bindValue(':result_id', $chosen_inline_result->getResultId());
654
            $sth->bindValue(':user_id', $user_id);
655
            $sth->bindValue(':location', $chosen_inline_result->getLocation());
656
            $sth->bindValue(':inline_message_id', $chosen_inline_result->getInlineMessageId());
657
            $sth->bindValue(':query', $chosen_inline_result->getQuery());
658
            $sth->bindValue(':created_at', $date);
659
660
            return $sth->execute();
661
        } catch (PDOException $e) {
662
            throw new TelegramException($e->getMessage());
663
        }
664
    }
665
666
    /**
667
     * Insert callback query request into database
668
     *
669
     * @param CallbackQuery $callback_query
670
     *
671
     * @return bool If the insert was successful
672
     * @throws TelegramException
673
     */
674
    public static function insertCallbackQueryRequest(CallbackQuery $callback_query)
675
    {
676
        if (!self::isDbConnected()) {
677
            return false;
678
        }
679
680
        try {
681
            $sth = self::$pdo->prepare('
682
                INSERT IGNORE INTO `' . TB_CALLBACK_QUERY . '`
683
                (`id`, `user_id`, `chat_id`, `message_id`, `inline_message_id`, `chat_instance`, `data`, `game_short_name`, `created_at`)
684
                VALUES
685
                (:id, :user_id, :chat_id, :message_id, :inline_message_id, :chat_instance, :data, :game_short_name, :created_at)
686
            ');
687
688
            $date    = self::getTimestamp();
689
            $user_id = null;
690
691
            $user = $callback_query->getFrom();
692
            if ($user instanceof User) {
693
                $user_id = $user->getId();
694
                self::insertUser($user, $date);
695
            }
696
697
            $message    = $callback_query->getMessage();
698
            $chat_id    = null;
699
            $message_id = null;
700
            if ($message instanceof Message) {
701
                $chat_id    = $message->getChat()->getId();
702
                $message_id = $message->getMessageId();
703
704
                $is_message = self::$pdo->query('
705
                    SELECT *
706
                    FROM `' . TB_MESSAGE . '`
707
                    WHERE `id` = ' . $message_id . '
708
                      AND `chat_id` = ' . $chat_id . '
709
                    LIMIT 1
710
                ')->rowCount();
711
712
                if ($is_message) {
713
                    self::insertEditedMessageRequest($message);
714
                } else {
715
                    self::insertMessageRequest($message);
716
                }
717
            }
718
719
            $sth->bindValue(':id', $callback_query->getId());
720
            $sth->bindValue(':user_id', $user_id);
721
            $sth->bindValue(':chat_id', $chat_id);
722
            $sth->bindValue(':message_id', $message_id);
723
            $sth->bindValue(':inline_message_id', $callback_query->getInlineMessageId());
724
            $sth->bindValue(':chat_instance', $callback_query->getChatInstance());
725
            $sth->bindValue(':data', $callback_query->getData());
726
            $sth->bindValue(':game_short_name', $callback_query->getGameShortName());
727
            $sth->bindValue(':created_at', $date);
728
729
            return $sth->execute();
730
        } catch (PDOException $e) {
731
            throw new TelegramException($e->getMessage());
732
        }
733
    }
734
735
    /**
736
     * Insert shipping query request into database
737
     *
738
     * @param ShippingQuery $shipping_query
739
     *
740
     * @return bool If the insert was successful
741
     * @throws TelegramException
742
     */
743 View Code Duplication
    public static function insertShippingQueryRequest(ShippingQuery $shipping_query)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
744
    {
745
        if (!self::isDbConnected()) {
746
            return false;
747
        }
748
749
        try {
750
            $sth = self::$pdo->prepare('
751
                INSERT IGNORE INTO `' . TB_SHIPPING_QUERY . '`
752
                (`id`, `user_id`, `invoice_payload`, `shipping_address`, `created_at`)
753
                VALUES
754
                (:id, :user_id, :invoice_payload, :shipping_address, :created_at)
755
            ');
756
757
            $date    = self::getTimestamp();
758
            $user_id = null;
759
760
            $user = $shipping_query->getFrom();
761
            if ($user instanceof User) {
762
                $user_id = $user->getId();
763
                self::insertUser($user, $date);
764
            }
765
766
            $sth->bindValue(':id', $shipping_query->getId());
767
            $sth->bindValue(':user_id', $user_id);
768
            $sth->bindValue(':invoice_payload', $shipping_query->getInvoicePayload());
769
            $sth->bindValue(':shipping_address', $shipping_query->getShippingAddress());
770
            $sth->bindValue(':created_at', $date);
771
772
            return $sth->execute();
773
        } catch (PDOException $e) {
774
            throw new TelegramException($e->getMessage());
775
        }
776
    }
777
778
    /**
779
     * Insert pre checkout query request into database
780
     *
781
     * @param PreCheckoutQuery $pre_checkout_query
782
     *
783
     * @return bool If the insert was successful
784
     * @throws TelegramException
785
     */
786
    public static function insertPreCheckoutQueryRequest(PreCheckoutQuery $pre_checkout_query)
787
    {
788
        if (!self::isDbConnected()) {
789
            return false;
790
        }
791
792
        try {
793
            $sth = self::$pdo->prepare('
794
                INSERT IGNORE INTO `' . TB_PRE_CHECKOUT_QUERY . '`
795
                (`id`, `user_id`, `currency`, `total_amount`, `invoice_payload`, `shipping_option_id`, `order_info`, `created_at`)
796
                VALUES
797
                (:id, :user_id, :currency, :total_amount, :invoice_payload, :shipping_option_id, :order_info, :created_at)
798
            ');
799
800
            $date    = self::getTimestamp();
801
            $user_id = null;
802
803
            $user = $pre_checkout_query->getFrom();
804
            if ($user instanceof User) {
805
                $user_id = $user->getId();
806
                self::insertUser($user, $date);
807
            }
808
809
            $sth->bindValue(':id', $pre_checkout_query->getId());
810
            $sth->bindValue(':user_id', $user_id);
811
            $sth->bindValue(':currency', $pre_checkout_query->getCurrency());
812
            $sth->bindValue(':total_amount', $pre_checkout_query->getTotalAmount());
813
            $sth->bindValue(':invoice_payload', $pre_checkout_query->getInvoicePayload());
814
            $sth->bindValue(':shipping_option_id', $pre_checkout_query->getShippingOptionId());
815
            $sth->bindValue(':order_info', $pre_checkout_query->getOrderInfo());
816
            $sth->bindValue(':created_at', $date);
817
818
            return $sth->execute();
819
        } catch (PDOException $e) {
820
            throw new TelegramException($e->getMessage());
821
        }
822
    }
823
824
    /**
825
     * Insert poll request into database
826
     *
827
     * @param Poll $poll
828
     *
829
     * @return bool If the insert was successful
830
     * @throws TelegramException
831
     */
832
    public static function insertPollRequest(Poll $poll)
833
    {
834
        if (!self::isDbConnected()) {
835
            return false;
836
        }
837
838
        try {
839
            $sth = self::$pdo->prepare('
840
                INSERT INTO `' . TB_POLL . '`
841
                (`id`, `question`, `options`, `is_closed`, `created_at`)
842
                VALUES
843
                (:id, :question, :options, :is_closed, :created_at)
844
                ON DUPLICATE KEY UPDATE
845
                    `options`   = VALUES(`options`),
846
                    `is_closed` = VALUES(`is_closed`)
847
            ');
848
849
            $sth->bindValue(':id', $poll->getId());
850
            $sth->bindValue(':question', $poll->getQuestion());
851
            $sth->bindValue(':options', self::entitiesArrayToJson($poll->getOptions()));
852
            $sth->bindValue(':is_closed', $poll->getIsClosed());
853
            $sth->bindValue(':created_at', self::getTimestamp());
854
855
            return $sth->execute();
856
        } catch (PDOException $e) {
857
            throw new TelegramException($e->getMessage());
858
        }
859
    }
860
861
    /**
862
     * Insert Message request in db
863
     *
864
     * @param Message $message
865
     *
866
     * @return bool If the insert was successful
867
     * @throws TelegramException
868
     */
869 6
    public static function insertMessageRequest(Message $message)
870
    {
871 6
        if (!self::isDbConnected()) {
872
            return false;
873
        }
874
875 6
        $date = self::getTimestamp($message->getDate());
876
877
        // Insert chat, update chat id in case it migrated
878 6
        $chat = $message->getChat();
879 6
        self::insertChat($chat, $date, $message->getMigrateToChatId());
880
881
        // Insert user and the relation with the chat
882 6
        $user = $message->getFrom();
883 6
        if ($user instanceof User) {
884 6
            self::insertUser($user, $date, $chat);
885
        }
886
887
        // Insert the forwarded message user in users table
888 6
        $forward_date = null;
889 6
        $forward_from = $message->getForwardFrom();
890 6
        if ($forward_from instanceof User) {
891
            self::insertUser($forward_from, $forward_date);
892
            $forward_from = $forward_from->getId();
893
            $forward_date = self::getTimestamp($message->getForwardDate());
894
        }
895 6
        $forward_from_chat = $message->getForwardFromChat();
896 6
        if ($forward_from_chat instanceof Chat) {
897
            self::insertChat($forward_from_chat, $forward_date);
898
            $forward_from_chat = $forward_from_chat->getId();
899
            $forward_date      = self::getTimestamp($message->getForwardDate());
900
        }
901
902
        // New and left chat member
903 6
        $new_chat_members_ids = null;
904 6
        $left_chat_member_id  = null;
905
906 6
        $new_chat_members = $message->getNewChatMembers();
907 6
        $left_chat_member = $message->getLeftChatMember();
908 6
        if (!empty($new_chat_members)) {
909
            foreach ($new_chat_members as $new_chat_member) {
910
                if ($new_chat_member instanceof User) {
911
                    // Insert the new chat user
912
                    self::insertUser($new_chat_member, $date, $chat);
913
                    $new_chat_members_ids[] = $new_chat_member->getId();
914
                }
915
            }
916
            $new_chat_members_ids = implode(',', $new_chat_members_ids);
917 6
        } elseif ($left_chat_member instanceof User) {
918
            // Insert the left chat user
919
            self::insertUser($left_chat_member, $date, $chat);
920
            $left_chat_member_id = $left_chat_member->getId();
921
        }
922
923
        try {
924 6
            $sth = self::$pdo->prepare('
925 6
                INSERT IGNORE INTO `' . TB_MESSAGE . '`
926
                (
927
                    `id`, `user_id`, `chat_id`, `date`, `forward_from`, `forward_from_chat`, `forward_from_message_id`,
928
                    `forward_signature`, `forward_sender_name`, `forward_date`,
929
                    `reply_to_chat`, `reply_to_message`, `edit_date`, `media_group_id`, `author_signature`, `text`, `entities`, `caption_entities`,
930
                    `audio`, `document`, `animation`, `game`, `photo`, `sticker`, `video`, `voice`, `video_note`, `caption`, `contact`,
931
                    `location`, `venue`, `poll`, `new_chat_members`, `left_chat_member`,
932
                    `new_chat_title`, `new_chat_photo`, `delete_chat_photo`, `group_chat_created`,
933
                    `supergroup_chat_created`, `channel_chat_created`, `migrate_to_chat_id`, `migrate_from_chat_id`,
934
                    `pinned_message`, `invoice`, `successful_payment`, `connected_website`, `passport_data`
935
                ) VALUES (
936
                    :message_id, :user_id, :chat_id, :date, :forward_from, :forward_from_chat, :forward_from_message_id,
937
                    :forward_signature, :forward_sender_name, :forward_date,
938
                    :reply_to_chat, :reply_to_message, :edit_date, :media_group_id, :author_signature, :text, :entities, :caption_entities,
939
                    :audio, :document, :animation, :game, :photo, :sticker, :video, :voice, :video_note, :caption, :contact,
940
                    :location, :venue, :poll, :new_chat_members, :left_chat_member,
941
                    :new_chat_title, :new_chat_photo, :delete_chat_photo, :group_chat_created,
942
                    :supergroup_chat_created, :channel_chat_created, :migrate_to_chat_id, :migrate_from_chat_id,
943
                    :pinned_message, :invoice, :successful_payment, :connected_website, :passport_data
944
                )
945
            ');
946
947 6
            $user_id = null;
948 6
            if ($user instanceof User) {
949 6
                $user_id = $user->getId();
950
            }
951 6
            $chat_id = $chat->getId();
952
953 6
            $reply_to_message    = $message->getReplyToMessage();
954 6
            $reply_to_message_id = null;
955 6
            if ($reply_to_message instanceof ReplyToMessage) {
956
                $reply_to_message_id = $reply_to_message->getMessageId();
957
                // please notice that, as explained in the documentation, reply_to_message don't contain other
958
                // reply_to_message field so recursion deep is 1
959
                self::insertMessageRequest($reply_to_message);
960
            }
961
962 6
            $sth->bindValue(':message_id', $message->getMessageId());
963 6
            $sth->bindValue(':chat_id', $chat_id);
964 6
            $sth->bindValue(':user_id', $user_id);
965 6
            $sth->bindValue(':date', $date);
966 6
            $sth->bindValue(':forward_from', $forward_from);
967 6
            $sth->bindValue(':forward_from_chat', $forward_from_chat);
968 6
            $sth->bindValue(':forward_from_message_id', $message->getForwardFromMessageId());
969 6
            $sth->bindValue(':forward_signature', $message->getForwardSignature());
970 6
            $sth->bindValue(':forward_sender_name', $message->getForwardSenderName());
971 6
            $sth->bindValue(':forward_date', $forward_date);
972
973 6
            $reply_to_chat_id = null;
974 6
            if ($reply_to_message_id !== null) {
975
                $reply_to_chat_id = $chat_id;
976
            }
977 6
            $sth->bindValue(':reply_to_chat', $reply_to_chat_id);
978 6
            $sth->bindValue(':reply_to_message', $reply_to_message_id);
979
980 6
            $sth->bindValue(':edit_date', $message->getEditDate());
981 6
            $sth->bindValue(':media_group_id', $message->getMediaGroupId());
982 6
            $sth->bindValue(':author_signature', $message->getAuthorSignature());
983 6
            $sth->bindValue(':text', $message->getText());
984 6
            $sth->bindValue(':entities', self::entitiesArrayToJson($message->getEntities()));
985 6
            $sth->bindValue(':caption_entities', self::entitiesArrayToJson($message->getCaptionEntities()));
986 6
            $sth->bindValue(':audio', $message->getAudio());
987 6
            $sth->bindValue(':document', $message->getDocument());
988 6
            $sth->bindValue(':animation', $message->getAnimation());
989 6
            $sth->bindValue(':game', $message->getGame());
990 6
            $sth->bindValue(':photo', self::entitiesArrayToJson($message->getPhoto()));
991 6
            $sth->bindValue(':sticker', $message->getSticker());
992 6
            $sth->bindValue(':video', $message->getVideo());
993 6
            $sth->bindValue(':voice', $message->getVoice());
994 6
            $sth->bindValue(':video_note', $message->getVideoNote());
995 6
            $sth->bindValue(':caption', $message->getCaption());
996 6
            $sth->bindValue(':contact', $message->getContact());
997 6
            $sth->bindValue(':location', $message->getLocation());
998 6
            $sth->bindValue(':venue', $message->getVenue());
999 6
            $sth->bindValue(':poll', $message->getPoll());
1000 6
            $sth->bindValue(':new_chat_members', $new_chat_members_ids);
1001 6
            $sth->bindValue(':left_chat_member', $left_chat_member_id);
1002 6
            $sth->bindValue(':new_chat_title', $message->getNewChatTitle());
1003 6
            $sth->bindValue(':new_chat_photo', self::entitiesArrayToJson($message->getNewChatPhoto()));
1004 6
            $sth->bindValue(':delete_chat_photo', $message->getDeleteChatPhoto());
1005 6
            $sth->bindValue(':group_chat_created', $message->getGroupChatCreated());
1006 6
            $sth->bindValue(':supergroup_chat_created', $message->getSupergroupChatCreated());
1007 6
            $sth->bindValue(':channel_chat_created', $message->getChannelChatCreated());
1008 6
            $sth->bindValue(':migrate_to_chat_id', $message->getMigrateToChatId());
1009 6
            $sth->bindValue(':migrate_from_chat_id', $message->getMigrateFromChatId());
1010 6
            $sth->bindValue(':pinned_message', $message->getPinnedMessage());
1011 6
            $sth->bindValue(':invoice', $message->getInvoice());
1012 6
            $sth->bindValue(':successful_payment', $message->getSuccessfulPayment());
1013 6
            $sth->bindValue(':connected_website', $message->getConnectedWebsite());
1014 6
            $sth->bindValue(':passport_data', $message->getPassportData());
1015
1016 6
            return $sth->execute();
1017
        } catch (PDOException $e) {
1018
            throw new TelegramException($e->getMessage());
1019
        }
1020
    }
1021
1022
    /**
1023
     * Insert Edited Message request in db
1024
     *
1025
     * @param Message $edited_message
1026
     *
1027
     * @return bool If the insert was successful
1028
     * @throws TelegramException
1029
     */
1030
    public static function insertEditedMessageRequest(Message $edited_message)
1031
    {
1032
        if (!self::isDbConnected()) {
1033
            return false;
1034
        }
1035
1036
        try {
1037
            $edit_date = self::getTimestamp($edited_message->getEditDate());
1038
1039
            // Insert chat
1040
            $chat = $edited_message->getChat();
1041
            self::insertChat($chat, $edit_date);
1042
1043
            // Insert user and the relation with the chat
1044
            $user = $edited_message->getFrom();
1045
            if ($user instanceof User) {
1046
                self::insertUser($user, $edit_date, $chat);
1047
            }
1048
1049
            $sth = self::$pdo->prepare('
1050
                INSERT IGNORE INTO `' . TB_EDITED_MESSAGE . '`
1051
                (`chat_id`, `message_id`, `user_id`, `edit_date`, `text`, `entities`, `caption`)
1052
                VALUES
1053
                (:chat_id, :message_id, :user_id, :edit_date, :text, :entities, :caption)
1054
            ');
1055
1056
            $user_id = null;
1057
            if ($user instanceof User) {
1058
                $user_id = $user->getId();
1059
            }
1060
1061
            $sth->bindValue(':chat_id', $chat->getId());
1062
            $sth->bindValue(':message_id', $edited_message->getMessageId());
1063
            $sth->bindValue(':user_id', $user_id);
1064
            $sth->bindValue(':edit_date', $edit_date);
1065
            $sth->bindValue(':text', $edited_message->getText());
1066
            $sth->bindValue(':entities', self::entitiesArrayToJson($edited_message->getEntities()));
1067
            $sth->bindValue(':caption', $edited_message->getCaption());
1068
1069
            return $sth->execute();
1070
        } catch (PDOException $e) {
1071
            throw new TelegramException($e->getMessage());
1072
        }
1073
    }
1074
1075
    /**
1076
     * Select Groups, Supergroups, Channels and/or single user Chats (also by ID or text)
1077
     *
1078
     * @param $select_chats_params
1079
     *
1080
     * @return array|bool
1081
     * @throws TelegramException
1082
     */
1083
    public static function selectChats($select_chats_params)
1084
    {
1085
        if (!self::isDbConnected()) {
1086
            return false;
1087
        }
1088
1089
        // Set defaults for omitted values.
1090
        $select = array_merge([
1091
            'groups'      => true,
1092
            'supergroups' => true,
1093
            'channels'    => true,
1094
            'users'       => true,
1095
            'date_from'   => null,
1096
            'date_to'     => null,
1097
            'chat_id'     => null,
1098
            'text'        => null,
1099
        ], $select_chats_params);
1100
1101
        if (!$select['groups'] && !$select['users'] && !$select['supergroups'] && !$select['channels']) {
1102
            return false;
1103
        }
1104
1105
        try {
1106
            $query = '
1107
                SELECT * ,
1108
                ' . TB_CHAT . '.`id` AS `chat_id`,
1109
                ' . TB_CHAT . '.`username` AS `chat_username`,
1110
                ' . TB_CHAT . '.`created_at` AS `chat_created_at`,
1111
                ' . TB_CHAT . '.`updated_at` AS `chat_updated_at`
1112
            ';
1113
            if ($select['users']) {
1114
                $query .= '
1115
                    , ' . TB_USER . '.`id` AS `user_id`
1116
                    FROM `' . TB_CHAT . '`
1117
                    LEFT JOIN `' . TB_USER . '`
1118
                    ON ' . TB_CHAT . '.`id`=' . TB_USER . '.`id`
1119
                ';
1120
            } else {
1121
                $query .= 'FROM `' . TB_CHAT . '`';
1122
            }
1123
1124
            // Building parts of query
1125
            $where  = [];
1126
            $tokens = [];
1127
1128
            if (!$select['groups'] || !$select['users'] || !$select['supergroups'] || !$select['channels']) {
1129
                $chat_or_user = [];
1130
1131
                $select['groups'] && $chat_or_user[] = TB_CHAT . '.`type` = "group"';
1132
                $select['supergroups'] && $chat_or_user[] = TB_CHAT . '.`type` = "supergroup"';
1133
                $select['channels'] && $chat_or_user[] = TB_CHAT . '.`type` = "channel"';
1134
                $select['users'] && $chat_or_user[] = TB_CHAT . '.`type` = "private"';
1135
1136
                $where[] = '(' . implode(' OR ', $chat_or_user) . ')';
1137
            }
1138
1139
            if (null !== $select['date_from']) {
1140
                $where[]              = TB_CHAT . '.`updated_at` >= :date_from';
1141
                $tokens[':date_from'] = $select['date_from'];
1142
            }
1143
1144
            if (null !== $select['date_to']) {
1145
                $where[]            = TB_CHAT . '.`updated_at` <= :date_to';
1146
                $tokens[':date_to'] = $select['date_to'];
1147
            }
1148
1149
            if (null !== $select['chat_id']) {
1150
                $where[]            = TB_CHAT . '.`id` = :chat_id';
1151
                $tokens[':chat_id'] = $select['chat_id'];
1152
            }
1153
1154
            if (null !== $select['text']) {
1155
                $text_like = '%' . strtolower($select['text']) . '%';
1156
                if ($select['users']) {
1157
                    $where[]          = '(
1158
                        LOWER(' . TB_CHAT . '.`title`) LIKE :text1
1159
                        OR LOWER(' . TB_USER . '.`first_name`) LIKE :text2
1160
                        OR LOWER(' . TB_USER . '.`last_name`) LIKE :text3
1161
                        OR LOWER(' . TB_USER . '.`username`) LIKE :text4
1162
                    )';
1163
                    $tokens[':text1'] = $text_like;
1164
                    $tokens[':text2'] = $text_like;
1165
                    $tokens[':text3'] = $text_like;
1166
                    $tokens[':text4'] = $text_like;
1167
                } else {
1168
                    $where[]         = 'LOWER(' . TB_CHAT . '.`title`) LIKE :text';
1169
                    $tokens[':text'] = $text_like;
1170
                }
1171
            }
1172
1173
            if (!empty($where)) {
1174
                $query .= ' WHERE ' . implode(' AND ', $where);
1175
            }
1176
1177
            $query .= ' ORDER BY ' . TB_CHAT . '.`updated_at` ASC';
1178
1179
            $sth = self::$pdo->prepare($query);
1180
            $sth->execute($tokens);
1181
1182
            return $sth->fetchAll(PDO::FETCH_ASSOC);
1183
        } catch (PDOException $e) {
1184
            throw new TelegramException($e->getMessage());
1185
        }
1186
    }
1187
1188
    /**
1189
     * Get Telegram API request count for current chat / message
1190
     *
1191
     * @param integer $chat_id
1192
     * @param string  $inline_message_id
1193
     *
1194
     * @return array|bool Array containing TOTAL and CURRENT fields or false on invalid arguments
1195
     * @throws TelegramException
1196
     */
1197
    public static function getTelegramRequestCount($chat_id = null, $inline_message_id = null)
1198
    {
1199
        if (!self::isDbConnected()) {
1200
            return false;
1201
        }
1202
1203
        try {
1204
            $sth = self::$pdo->prepare('SELECT
1205
                (SELECT COUNT(DISTINCT `chat_id`) FROM `' . TB_REQUEST_LIMITER . '` WHERE `created_at` >= :created_at_1) AS LIMIT_PER_SEC_ALL,
1206
                (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,
1207
                (SELECT COUNT(*) FROM `' . TB_REQUEST_LIMITER . '` WHERE `created_at` >= :created_at_minute AND `chat_id` = :chat_id_2) AS LIMIT_PER_MINUTE
1208
            ');
1209
1210
            $date        = self::getTimestamp();
1211
            $date_minute = self::getTimestamp(strtotime('-1 minute'));
1212
1213
            $sth->bindValue(':chat_id_1', $chat_id);
1214
            $sth->bindValue(':chat_id_2', $chat_id);
1215
            $sth->bindValue(':inline_message_id', $inline_message_id);
1216
            $sth->bindValue(':created_at_1', $date);
1217
            $sth->bindValue(':created_at_2', $date);
1218
            $sth->bindValue(':created_at_minute', $date_minute);
1219
1220
            $sth->execute();
1221
1222
            return $sth->fetch();
1223
        } catch (PDOException $e) {
1224
            throw new TelegramException($e->getMessage());
1225
        }
1226
    }
1227
1228
    /**
1229
     * Insert Telegram API request in db
1230
     *
1231
     * @param string $method
1232
     * @param array  $data
1233
     *
1234
     * @return bool If the insert was successful
1235
     * @throws TelegramException
1236
     */
1237
    public static function insertTelegramRequest($method, $data)
1238
    {
1239
        if (!self::isDbConnected()) {
1240
            return false;
1241
        }
1242
1243
        try {
1244
            $sth = self::$pdo->prepare('INSERT INTO `' . TB_REQUEST_LIMITER . '`
1245
                (`method`, `chat_id`, `inline_message_id`, `created_at`)
1246
                VALUES
1247
                (:method, :chat_id, :inline_message_id, :created_at);
1248
            ');
1249
1250
            $chat_id           = isset($data['chat_id']) ? $data['chat_id'] : null;
1251
            $inline_message_id = isset($data['inline_message_id']) ? $data['inline_message_id'] : null;
1252
1253
            $sth->bindValue(':chat_id', $chat_id);
1254
            $sth->bindValue(':inline_message_id', $inline_message_id);
1255
            $sth->bindValue(':method', $method);
1256
            $sth->bindValue(':created_at', self::getTimestamp());
1257
1258
            return $sth->execute();
1259
        } catch (PDOException $e) {
1260
            throw new TelegramException($e->getMessage());
1261
        }
1262
    }
1263
1264
    /**
1265
     * Bulk update the entries of any table
1266
     *
1267
     * @param string $table
1268
     * @param array  $fields_values
1269
     * @param array  $where_fields_values
1270
     *
1271
     * @return bool
1272
     * @throws TelegramException
1273
     */
1274 3
    public static function update($table, array $fields_values, array $where_fields_values)
1275
    {
1276 3
        if (empty($fields_values) || !self::isDbConnected()) {
1277
            return false;
1278
        }
1279
1280
        try {
1281
            // Building parts of query
1282 3
            $tokens = $fields = $where = [];
1283
1284
            // Fields with values to update
1285 3 View Code Duplication
            foreach ($fields_values as $field => $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1286 3
                $token          = ':' . count($tokens);
1287 3
                $fields[]       = "`{$field}` = {$token}";
1288 3
                $tokens[$token] = $value;
1289
            }
1290
1291
            // Where conditions
1292 3 View Code Duplication
            foreach ($where_fields_values as $field => $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1293 3
                $token          = ':' . count($tokens);
1294 3
                $where[]        = "`{$field}` = {$token}";
1295 3
                $tokens[$token] = $value;
1296
            }
1297
1298 3
            $sql = 'UPDATE `' . $table . '` SET ' . implode(', ', $fields);
1299 3
            $sql .= count($where) > 0 ? ' WHERE ' . implode(' AND ', $where) : '';
1300
1301 3
            return self::$pdo->prepare($sql)->execute($tokens);
1302
        } catch (PDOException $e) {
1303
            throw new TelegramException($e->getMessage());
1304
        }
1305
    }
1306
1307
    /**
1308
     * Run DB migrations using Phinx.
1309
     *
1310
     * @return bool
1311
     */
1312
    public static function runMigrations()
1313
    {
1314
        if (!self::isDbConnected()) {
1315
            return false;
1316
        }
1317
1318
        // Need to require autoloader to get Phinx classes loaded.
1319
        require_once __DIR__ . '/../vendor/autoload.php';
1320
1321
        $config = new Config([
1322
            'paths'        => [
1323
                'migrations' => __DIR__ . '/../utils/db-migrations',
1324
            ],
1325
            'environments' => [
1326
                'default_migration_table' => self::$table_prefix . 'phinx_migrations',
1327
                'default_database'        => 'core',
1328
                'core'                    => [
1329
                    'connection'   => self::getPdo(),
1330
                    'table_prefix' => self::$table_prefix,
1331
                    'name'         => self::$mysql_credentials['database'],
1332
                ],
1333
            ],
1334
        ]);
1335
1336
        $manager = new Manager($config, $input = new ArgvInput(), $output = new ConsoleOutput());
1337
1338
        $output->writeln(date('Y-m-d H:i:s') . ' - Migration started.');
1339
1340
        switch ($input->getFirstArgument()) {
1341
            case 'rollback':
1342
                $manager->rollback('core');
1343
                break;
1344
            default:
1345
                $manager->migrate('core');
1346
        }
1347
1348
        $output->writeln(date('Y-m-d H:i:s') . ' - Migration completed.');
1349
1350
        return true;
1351
    }
1352
}
1353