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
165
166
167
168
169
|
<?php
namespace Digitigrade;
use Digitigrade\Model\UserAccount;
class UserSettings {
private const DEFINITIONS_INI_PATH = __DIR__ . '/../settings.user.ini';
private \PDO $db;
private array $info;
private UserAccount $user;
public function __construct(UserAccount $user) {
$this->user = $user;
$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 user_setting WHERE name = ? AND user_id = ?');
$stmt->execute([$key, $this->user->id]);
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 user_setting(user_id, name, value) VALUES (?, ?, ?)
ON CONFLICT (user_id, name) DO UPDATE SET value = EXCLUDED.value
END);
$stmt->execute([$this->user->id, $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 user_setting WHERE name = ? AND user_id = ?');
$stmt->execute([$key, $this->user->id]);
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 user_setting WHERE name = ? AND user_id = ?');
$stmt->execute([$key, $this->user->id]);
}
/**
* 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->prepare('SELECT name, value FROM user_setting WHERE user_id = ?');
$stmt->execute([$this->user->id]);
$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 user_setting WHERE name ^@ ? AND user_id = ?');
$stmt->execute(["$prefix.", $this->user->id]);
$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 (name, description, default value) for a given setting.
* @param string $key which setting to look up
* @return ?array{item: string, value: string} 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);
}
}
|