aboutsummaryrefslogtreecommitdiffhomepage
path: root/Digitigrade/GlobalSettings.php
blob: e8bbe59e20da778a274e934c05374c811ada2e88 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
<?php
namespace Digitigrade;

class GlobalSettings extends Singleton {
    private const DEFINITIONS_INI_PATH = __DIR__ . '/../settings.global.ini';

    private \PDO $db;
    private array $info;

    protected function __construct() {
        $this->db = Db::getInstance()->getPdo();
        if (!$this->get('settings.initialised')) {
            $this->resetAll();
        }
    }

    /**
     * Gets a setting's value.
     * @param string $key which setting to get
     * @return ?string the value, or null if not set
     */
    public function get(string $key): ?string {
        $stmt = $this->db->prepare('SELECT value FROM global_setting WHERE name = ?');
        $stmt->execute([$key]);
        return $stmt->fetchColumn(0) ?: null;
    }

    /**
     * Gets a boolean setting's value.
     * @param string $key which setting to get
     * @return ?bool the value, or null if not set
     */
    public function getBool(string $key): ?bool {
        return match ($this->get($key)) {
            '', 'false' => false,
            '1', 'true' => true,
            default => null
        };
    }

    /**
     * Sets the value of a setting.
     * @param string $key which setting to modify
     * @param string $value the new value
     * @return void
     */
    public function set(string $key, string $value) {
        $stmt = $this->db->prepare(<<<END
        INSERT INTO global_setting(name, value) VALUES (?, ?)
        ON CONFLICT (name) DO UPDATE SET value = EXCLUDED.value
        END);
        $stmt->execute([$key, $value]);
    }

    public function setBool(string $key, bool $value) {
        $this->set($key, $value ? 'true' : 'false');
    }

    /**
     * Checks whether a setting is set.
     * @param string $key which setting to check
     * @return bool if it's set (has a value) or not
     */
    public function isset(string $key): bool {
        $stmt = $this->db->prepare('SELECT count(*) FROM global_setting WHERE name = ?');
        $stmt->execute([$key]);
        return $stmt->fetchColumn(0) > 0;
    }

    /**
     * Unsets a setting.
     * @param string $key which setting to remove
     * @return void
     */
    public function unset(string $key) {
        $stmt = $this->db->prepare('DELETE FROM global_setting WHERE name = ?');
        $stmt->execute([$key]);
    }

    /**
     * Gets a list of all currently-set settings.
     * @return array{key: string, value: string} array of keys to values
     */
    public function getAll(): array {
        $stmt = $this->db->query('SELECT name, value FROM global_setting');
        $items = $stmt->fetchAll();
        $result = [];
        foreach ($items as $row) {
            $result[$row['name']] = $row['value'];
        }
        return $result;
    }

    /**
     * Gets a list of all settings in a given prefix.
     * @param string $prefix prefix to look in (not including the trailing dot)
     * @return array{key: string, value: string} array of keys to values
     */
    public function getAllInPrefix(string $prefix): array {
        $stmt = $this->db->prepare('SELECT name, value FROM global_setting WHERE name ^@ ?');
        $stmt->execute(["$prefix."]);
        $items = $stmt->fetchAll();
        $result = [];
        foreach ($items as $row) {
            $result[$row['name']] = $row['value'];
        }
        return $result;
    }

    /**
     * Gets a list of all first-level prefixes.
     * @return string[]
     */
    public function getAllPrefixes(): array {
        return array_unique(array_map(
            fn($x) => explode('.', $x, 2)[0],
            array_keys($this->getAll())
        ));
    }

    /**
     * Gets information (default value, maybe type) for a given setting.
     * @param string $key which setting to look up
     * @return ?array associative array of info,
     * or null if none is available
     */
    public function getInfo(string $key): ?array {
        $this->loadDefinitions();
        return $this->info[$key] ?? null;
    }

    /**
     * Merges new keys from the settings definition file into the settings
     * without overwriting existing values.
     * @return void
     */
    public function mergeUpdates() {
        $this->initialise(false);
    }

    /**
     * Sets all defined settings back to their default values.
     * @return void
     */
    public function resetAll() {
        $this->initialise(true);
    }

    private function loadDefinitions() {
        if (!isset($this->info)) {
            $this->info = parse_ini_file(self::DEFINITIONS_INI_PATH, process_sections: true);
        }
    }

    private function initialise(bool $overwriteExisting) {
        $this->loadDefinitions();
        foreach ($this->info as $key => $setting) {
            if ($overwriteExisting || !$this->isset($key)) {
                $this->set($key, $setting['default']);
            }
        }
        $this->set('settings.initialised', true);
    }
}