Subversion Repositories oidplus

Rev

Rev 1116 | Rev 1172 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
1086 daniel-mar 5
 * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
2 daniel-mar 6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
1050 daniel-mar 20
namespace ViaThinkSoft\OIDplus;
511 daniel-mar 21
 
1086 daniel-mar 22
// phpcs:disable PSR1.Files.SideEffects
23
\defined('INSIDE_OIDPLUS') or die;
24
// phpcs:enable PSR1.Files.SideEffects
25
 
261 daniel-mar 26
// OIDplusConfig contains settings that are stored in the database.
294 daniel-mar 27
// Not to be confused with OIDplusBaseConfig which is the basic ("static")
28
// configuration stored in userdata/baseconfig/config.inc.php,
261 daniel-mar 29
// e.g. database access credentials.
730 daniel-mar 30
class OIDplusConfig extends OIDplusBaseClass implements OIDplusGetterSetterInterface {
2 daniel-mar 31
 
1130 daniel-mar 32
        /**
33
         *
34
         */
269 daniel-mar 35
        /*public*/ const PROTECTION_EDITABLE = 0;
1130 daniel-mar 36
 
37
        /**
38
         *
39
         */
269 daniel-mar 40
        /*public*/ const PROTECTION_READONLY = 1;
1130 daniel-mar 41
 
42
        /**
43
         *
44
         */
269 daniel-mar 45
        /*public*/ const PROTECTION_HIDDEN   = 2;
263 daniel-mar 46
 
1130 daniel-mar 47
        /**
48
         * @var bool
49
         */
326 daniel-mar 50
        protected $configTableReadOnce = false; // this ensures that all $values and $descriptions were read
51
 
1130 daniel-mar 52
        /**
53
         * @var array
54
         */
75 daniel-mar 55
        protected $values = array();
1130 daniel-mar 56
 
57
        /**
58
         * @var array
59
         */
295 daniel-mar 60
        protected $descriptions = array();
1130 daniel-mar 61
 
62
        /**
63
         * @var array
64
         */
682 daniel-mar 65
        protected $protectSettings = array();
1130 daniel-mar 66
 
67
        /**
68
         * @var array
69
         */
682 daniel-mar 70
        protected $visibleSettings = array();
1130 daniel-mar 71
 
72
        /**
73
         * @var array
74
         */
263 daniel-mar 75
        protected $validateCallbacks = array();
13 daniel-mar 76
 
1116 daniel-mar 77
        /**
78
         * @param string $name
79
         * @param string $description
80
         * @param string $init_value
81
         * @param int $protection
1130 daniel-mar 82
         * @param callable|null $validateCallback
1116 daniel-mar 83
         * @return void
84
         * @throws OIDplusException
85
         */
1130 daniel-mar 86
        public function prepareConfigKey(string $name, string $description, string $init_value, int $protection, callable $validateCallback=null) {
326 daniel-mar 87
                // Check if the protection flag is valid
263 daniel-mar 88
                switch ($protection) {
89
                        case OIDplusConfig::PROTECTION_EDITABLE:
90
                                $protected = 0;
91
                                $visible   = 1;
92
                                break;
93
                        case OIDplusConfig::PROTECTION_READONLY:
94
                                $protected = 1;
95
                                $visible   = 1;
96
                                break;
97
                        case OIDplusConfig::PROTECTION_HIDDEN:
98
                                $protected = 1;
99
                                $visible   = 0;
100
                                break;
101
                        default:
360 daniel-mar 102
                                throw new OIDplusException(_L('Invalid protection flag, use OIDplusConfig::PROTECTION_* constants'));
263 daniel-mar 103
                }
295 daniel-mar 104
 
326 daniel-mar 105
                // Check length limitations given by the database tables
166 daniel-mar 106
                if (strlen($name) > 50) {
360 daniel-mar 107
                        throw new OIDplusException(_L('Config key name "%1" is too long (max %2).',$name,50));
166 daniel-mar 108
                }
109
                if (strlen($description) > 255) {
360 daniel-mar 110
                        throw new OIDplusException(_L('Description for config key "%1" is too long (max %2).',$name,255));
166 daniel-mar 111
                }
326 daniel-mar 112
 
113
                // Read all values and descriptions from the database once.
150 daniel-mar 114
                $this->buildConfigArray();
326 daniel-mar 115
 
116
                // Figure out if we need to create/update something at database level
150 daniel-mar 117
                if (!isset($this->values[$name])) {
326 daniel-mar 118
                        // Case A: The config setting does not exist in the database. So we create it now.
614 daniel-mar 119
                        try {
120
                                OIDplus::db()->query("insert into ###config (name, description, value, protected, visible) values (?, ?, ?, ?, ?)", array($name, $description, $init_value, $protected, $visible));
1050 daniel-mar 121
                        } catch (\Exception $e) {
614 daniel-mar 122
                                // After a software update that introduced a new config setting,
123
                                // there will be a race-condition at this place, because
124
                                // jsTree and content are loading simultaneously!
125
                                // So we ignore the error here.
126
                        }
155 daniel-mar 127
                        $this->values[$name] = $init_value;
295 daniel-mar 128
                        $this->descriptions[$name] = $description;
682 daniel-mar 129
                        $this->protectSettings[$name] = $protected;
130
                        $this->visibleSettings[$name] = $visible;
326 daniel-mar 131
                } else {
132
                        // Case B: The config setting exists ...
133
                        if ($this->descriptions[$name] != $description) {
134
                                // ... but the human readable description is different.
135
                                // We want to give the plugin authors the possibility to automatically update the config descriptions for their plugins
136
                                // So we just edit the description
137
                                OIDplus::db()->query("update ###config set description = ? where name = ?", array($description, $name));
138
                                $this->descriptions[$name] = $description;
139
                        }
682 daniel-mar 140
                        if ($this->protectSettings[$name] != $protected) {
141
                                OIDplus::db()->query("update ###config set protected = ? where name = ?", array($protected, $name));
142
                                $this->protectSettings[$name] = $protected;
143
                        }
144
                        if ($this->visibleSettings[$name] != $visible) {
145
                                OIDplus::db()->query("update ###config set visible = ? where name = ?", array($visible, $name));
146
                                $this->visibleSettings[$name] = $visible;
147
                        }
150 daniel-mar 148
                }
326 daniel-mar 149
 
150
                // Register the validation callback
263 daniel-mar 151
                if (!is_null($validateCallback)) {
152
                        $this->validateCallbacks[$name] = $validateCallback;
153
                }
13 daniel-mar 154
        }
155
 
1116 daniel-mar 156
        /**
157
         * @return void
158
         * @throws OIDplusException
159
         */
326 daniel-mar 160
        public function clearCache() {
161
                $this->configTableReadOnce = false;
162
                $this->buildConfigArray();
163
        }
164
 
1116 daniel-mar 165
        /**
166
         * @return void
167
         * @throws OIDplusException
168
         */
150 daniel-mar 169
        protected function buildConfigArray() {
326 daniel-mar 170
                if ($this->configTableReadOnce) return;
171
 
172
                $this->values = array();
173
                $this->descriptions = array();
682 daniel-mar 174
                $this->protectSettings = array();
175
                $this->visibleSettings = array();
176
                $res = OIDplus::db()->query("select name, description, protected, visible, value from ###config");
326 daniel-mar 177
                while ($row = $res->fetch_object()) {
178
                        $this->values[$row->name] = $row->value;
179
                        $this->descriptions[$row->name] = $row->description;
682 daniel-mar 180
                        $this->protectSettings[$row->name] = $row->protected;
181
                        $this->visibleSettings[$row->name] = $row->visible;
75 daniel-mar 182
                }
326 daniel-mar 183
 
184
                $this->configTableReadOnce = true;
150 daniel-mar 185
        }
75 daniel-mar 186
 
1116 daniel-mar 187
        /**
188
         * @param string $name
189
         * @param mixed|null $default
190
         * @return mixed|null
191
         * @throws OIDplusException
192
         */
193
        public function getValue(string $name, $default=null) {
326 daniel-mar 194
                // Read all config settings once and write them in array $this->values
150 daniel-mar 195
                $this->buildConfigArray();
326 daniel-mar 196
 
197
                // Now we can see if our desired attribute is available
1130 daniel-mar 198
                return $this->values[$name] ?? $default;
46 daniel-mar 199
        }
200
 
1116 daniel-mar 201
        /**
202
         * @param string $name
203
         * @return bool
204
         * @throws OIDplusException
205
         */
206
        public function exists(string $name): bool {
326 daniel-mar 207
                return !is_null($this->getValue($name, null));
74 daniel-mar 208
        }
209
 
1116 daniel-mar 210
        /**
211
         * @param string $name
212
         * @param mixed $value
213
         * @return void
214
         * @throws OIDplusException
215
         */
216
        public function setValue(string $name, $value) {
574 daniel-mar 217
                // Read all config settings once and write them in array $this->values
218
                $this->buildConfigArray();
219
 
326 daniel-mar 220
                if (isset($this->values[$name])) {
574 daniel-mar 221
                        // Avoid unnecessary database writes
326 daniel-mar 222
                        if ($this->values[$name] == $value) return;
574 daniel-mar 223
                } else {
224
                        throw new OIDplusException(_L('Config value "%1" cannot be written because it was not prepared!', $name));
326 daniel-mar 225
                }
226
 
263 daniel-mar 227
                // Give plugins the possibility to stop the process by throwing an Exception (e.g. if the value is invalid)
326 daniel-mar 228
                // Required is that the plugin previously prepared the config setting using prepareConfigKey()
263 daniel-mar 229
                if (isset($this->validateCallbacks[$name])) {
230
                        $this->validateCallbacks[$name]($value);
14 daniel-mar 231
                }
257 daniel-mar 232
 
14 daniel-mar 233
                // Now change the value in the database
261 daniel-mar 234
                OIDplus::db()->query("update ###config set value = ? where name = ?", array($value, $name));
66 daniel-mar 235
                $this->values[$name] = $value;
14 daniel-mar 236
        }
237
 
1116 daniel-mar 238
        /**
239
         * @param string $name
240
         * @param string $value
241
         * @return void
242
         * @throws OIDplusException
243
         */
244
        public function setValueNoCallback(string $name, string $value) {
672 daniel-mar 245
                // Read all config settings once and write them in array $this->values
246
                $this->buildConfigArray();
247
 
248
                if (isset($this->values[$name])) {
249
                        // Avoid unnecessary database writes
250
                        if ($this->values[$name] == $value) return;
251
                } else {
252
                        throw new OIDplusException(_L('Config value "%1" cannot be written because it was not prepared!', $name));
253
                }
254
 
255
                // Now change the value in the database
256
                OIDplus::db()->query("update ###config set value = ? where name = ?", array($value, $name));
257
                $this->values[$name] = $value;
258
        }
259
 
1116 daniel-mar 260
        /**
261
         * @param string $name
262
         * @return void
263
         * @throws OIDplusException
264
         */
265
        public function delete(string $name) {
326 daniel-mar 266
                if ($this->configTableReadOnce) {
267
                        if (isset($this->values[$name])) {
268
                                OIDplus::db()->query("delete from ###config where name = ?", array($name));
269
                        }
270
                } else {
271
                        // We do not know if the value exists.
272
                        // buildConfigArray() would do many reads which are unnecessary.
273
                        // So we just do a MySQL command to delete the stuff:
294 daniel-mar 274
                        OIDplus::db()->query("delete from ###config where name = ?", array($name));
275
                }
326 daniel-mar 276
 
277
                unset($this->values[$name]);
278
                unset($this->descriptions[$name]);
279
                unset($this->validateCallbacks[$name]);
682 daniel-mar 280
                unset($this->protectSettings[$name]);
281
                unset($this->visibleSettings[$name]);
294 daniel-mar 282
        }
283
 
569 daniel-mar 284
}