Passed
Push — master ( 86fe81...69b6a3 )
by Dispositif
02:31
created

Stats::decrement()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 6
c 1
b 0
f 1
dl 0
loc 9
rs 10
cc 2
nc 2
nop 1
1
<?php
2
/*
3
 * This file is part of dispositif/wikibot application (@github)
4
 * 2019-2023 © Philippe M./Irønie  <[email protected]>
5
 * For the full copyright and MIT license information, view the license file.
6
 */
7
8
declare(strict_types=1);
9
10
namespace App\Infrastructure\Monitor;
11
12
use Exception;
13
use SQLite3;
14
15
/**
16
 * SQLite3 base: stats.db
17
 * tables: tagnum, tagnum_daily, tagnum_monthly
18
 */
19
class Stats
20
{
21
    protected const DEFAULT_FILEPATH = __DIR__ . '/../../../log/stats.db';
22
    protected const MAX_TAG_LENGTH = 100;
23
24
    protected SQLite3 $db;
25
26
    public function __construct()
27
    {
28
        if (!class_exists('SQLite3')) {
29
            throw new Exception('Stats ERROR : SQLite 3 NOT supported.');
30
        }
31
        $this->db = new SQLite3(getenv('STATS_FILEPATH') ?: self::DEFAULT_FILEPATH);
32
        $this->createTableIfNotExists();
33
    }
34
35
    public function increment(string $tag): bool
36
    {
37
        $tag = $this->formatTag($tag);
38
39
        $this->upsertTag(sprintf('%s.%s', date('Ymd'), $tag), 'tagnum_daily');
40
        $this->upsertTag(sprintf('%s.%s', date('Ym'), $tag), 'tagnum_monthly');
41
42
        return $this->upsertTag($tag);
43
    }
44
45
    private function formatTag(string $tag)
46
    {
47
        return mb_substr($tag, 0, self::MAX_TAG_LENGTH);
48
    }
49
50
    public function set(string $tag, int $num): bool
51
    {
52
        $tag = $this->formatTag($tag);
53
        try {
54
            return $this->db->exec('INSERT OR REPLACE INTO tagnum (tag,num) VALUES("' . $tag . '", ' . $num . ')');
55
        } catch (Exception $e) {
56
            return false;
57
        }
58
    }
59
60
    public function decrement(string $tag): bool
61
    {
62
        $tag = $this->formatTag($tag);
63
        try {
64
            return $this->db->exec(
65
                'INSERT INTO tagnum (tag) VALUES("' . $tag . '") ON CONFLICT(tag) DO UPDATE SET num=num-1'
66
            );
67
        } catch (Exception $e) {
68
            return false;
69
        }
70
    }
71
72
    public function select(string $tag): ?int
73
    {
74
        $tag = $this->formatTag($tag);
75
        try {
76
            $stmt = $this->db->prepare('SELECT tag,num FROM tagnum WHERE tag LIKE :tag');
77
            $stmt->bindValue(':tag', $tag, SQLITE3_TEXT);
78
            $result = $stmt->execute();
79
80
            return $result ? $result->fetchArray(SQLITE3_ASSOC)['num'] : null;
0 ignored issues
show
introduced by
$result is of type SQLite3Result, thus it always evaluated to true.
Loading history...
81
        } catch (Exception $e) {
82
            return null;
83
        }
84
    }
85
86
    protected function createTableIfNotExists(): bool
87
    {
88
        try {
89
            $this->db->exec('CREATE TABLE if not exists tagnum_monthly (
90
                tag VARCHAR(' . self::MAX_TAG_LENGTH . ') NOT NULL PRIMARY KEY,
91
                num int(11) NOT NULL DEFAULT 1
92
            )');
93
94
            $this->db->exec('CREATE TABLE if not exists tagnum_daily (
95
                tag VARCHAR(' . self::MAX_TAG_LENGTH . ') NOT NULL PRIMARY KEY,
96
                num int(11) NOT NULL DEFAULT 1
97
            )');
98
99
            return $this->db->exec('CREATE TABLE if not exists tagnum (
100
                tag VARCHAR(' . self::MAX_TAG_LENGTH . ') NOT NULL PRIMARY KEY,
101
                num int(11) NOT NULL DEFAULT 1
102
            )');
103
        } catch (Exception $e) {
104
            return false;
105
        }
106
    }
107
108
    protected function upsertTag(string $tag, string $table = 'tagnum'): bool
109
    {
110
        // `num` default value is 1 so insert is enough to set num=1
111
        try {
112
            // upsert :)
113
            return $this->db->exec(
114
                'INSERT INTO '.$table.' (tag) VALUES("' . $tag . '") ON CONFLICT(tag) DO UPDATE SET num=num+1'
115
            );
116
        } catch (Exception $e) {
117
            return false;
118
        }
119
    }
120
}