Completed
Push — master ( fa4a65...9c9e24 )
by Justin
03:06
created

Settings::saveAsync()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 3
eloc 3
nc 3
nop 0
dl 0
loc 4
rs 10
c 1
b 0
f 1
1
<?php
2
3
/**
4
 * Copyright (c) 2018 Justin Kuenzel (jukusoft.com)
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
/**
20
 * this class is responsible for global settings
21
 *
22
 * @copyright (c) 2018, jukusoft.com (Justin Kuenzel), Pascal Reintjens
23
 * @license Apache 2.0
24
 * @since 1.0.0
25
 */
26
class Settings {
27
28
	//in-memory cache of settings
29
	protected static $settings = array();
30
31
	//flag, if global settings was initialized
32
	protected static $initialized = false;
33
34
	protected static $async_save_list = array();
35
36
	/**
37
	 * get value of setting
38
	 *
39
	 * @package com.jukusoft.cms.settings
40
	 *
41
	 * @param key setting
42
	 *
43
	 * @throws IllegalStateException of key doesnt exists and no default value is set
44
	 *
45
	 * @return mixed or null, if key doesnt exists in database / default value, if set
46
	 */
47
	public static function get (string $key, $default_value = null) {
48
		//load settings if neccessary
49
		self::loadSettingsIfAbsent();
50
51
		if (!isset(self::$settings[$key])) {
52
			if ($default_value !== null) {
53
				return $default_value;
54
			} else {
55
				throw new IllegalStateException("Settings key '" . $key . "' doesnt exists.");
56
			}
57
		} else {
58
			return unserialize(self::$settings[$key]);
59
		}
60
	}
61
62
	/**
63
	 * set setting
64
	 *
65
	 * @param $key setting
66
	 * @param $value mixed value to set
67
	 */
68
	public static function set (string $key, $value) {
69
		//serialize data
70
		$value = serialize($value);
71
72
		//update database
73
		Database::getInstance()->execute("UPDATE `{praefix}global_settings` SET `value` = :value WHERE `key` = :key;", array(
74
			'value' => $value,
75
			'key' => $key
76
		));
77
78
		//update local in-memory cache
79
		self::$settings[$key] = $value;
80
81
		//clear cache (area "global_settings")
82
		Cache::clear("global_settings");
83
	}
84
85
	public static function setAsync (string $key, $value) {
86
		self::$async_save_list[$key] = serialize($value);
87
	}
88
89
	public static function saveAsync () {
90
		if (!empty(self::$async_save_list)) {
91
			foreach (self::$async_save_list as $key=>$value) {
92
				Settings::set($key, $value);
93
			}
94
		}
95
	}
96
97
	/**
98
	 * check if settings key exists
99
	 *
100
	 * @param $key string settings key
101
	 *
102
	 * @return true if setting key exists
103
	 */
104
	public static function contains (string $key) : bool {
105
		//load settings if neccessary
106
		self::loadSettingsIfAbsent();
107
108
		//escape key
109
		//$key = Database::getInstance()->escape($key);
110
111
		return isset(self::$settings[$key]);
0 ignored issues
show
Bug Best Practice introduced by
The expression return IssetNode returns the type boolean which is incompatible with the documented return type true.
Loading history...
112
	}
113
114
	/**
115
	 * set setting if key is absent
116
	 *
117
	 * @param $key setting
118
	 * @param $value mixed value to set
119
	 */
120
	public static function setIfAbsent (string $key, $value) {
121
		self::loadSettingsIfAbsent();
122
123
		if (!isset(self::$settings[$key])) {
124
			self::set($key, $value);
125
		}
126
	}
127
128
	/**
129
	 * create setting (so it can be shown on settings page)
130
	 */
131
	public static function create (string $key, $value, string $title, string $description, string $owner, string $category = "general", string $datatype = "DataType_String", $datatype_params = "", bool $editable = true, $visible_permissions = "can_see_global_settings", $change_permissions = "can_change_global_settings", int $order = 10, string $icon_path = "none", string $last_update = "0000-00-00 00:00:00") {
0 ignored issues
show
Unused Code introduced by
The parameter $last_update is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

131
	public static function create (string $key, $value, string $title, string $description, string $owner, string $category = "general", string $datatype = "DataType_String", $datatype_params = "", bool $editable = true, $visible_permissions = "can_see_global_settings", $change_permissions = "can_change_global_settings", int $order = 10, string $icon_path = "none", /** @scrutinizer ignore-unused */ string $last_update = "0000-00-00 00:00:00") {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
132
		self::loadSettingsIfAbsent();
133
134
		if (strlen($key) > 255) {
135
			throw new IllegalArgumentException("max key length is 255, your key: " . $key);
136
		}
137
138
		//check, if setting already exists
139
		/*if (isset(self::$settings[$key])) {
140
			throw new IllegalArgumentException("global setting key '" . $key . "' already exists in database.");
141
		}*/
142
143
		//allow more than one possible permission as array
144
		if (is_array($visible_permissions)) {
145
			$visible_permissions = implode("|", $visible_permissions);
146
		}
147
148
		//allow more than one possible permission as array
149
		if (is_array($change_permissions)) {
150
			$change_permissions = implode("|", $change_permissions);
151
		}
152
153
		//serialize value
154
		$value = serialize($value);
155
		$datatype_params = serialize($datatype_params);
156
157
		//insert setting into database
158
		Database::getInstance()->execute("INSERT INTO `{praefix}global_settings` (
159
			`key`, `value`, `title`, `description`, `visible_permission`, `change_permission`, `owner`, `order`, `icon_path`, `last_update`, `datatype`, `datatype_params`, `editable`, `category`, `activated`
160
		) VALUES (
161
			:key, :value, :title, :description, :visible_permissions, :change_permissions, :owner, :order, :icon_path, '0000-00-00 00:00:00', :datatype, :datatype_params, :editable, :category, :activated
162
		) ON DUPLICATE KEY UPDATE `title` = :title, `description` = :description, `visible_permission` = :visible_permissions, `change_permission` = :change_permissions, `owner` = :owner, `order` = :order, `icon_path` = :icon_path, `last_update` = CURRENT_TIMESTAMP, `datatype` = :datatype, `datatype_params` = :datatype_params, `editable` = :editable, `category` = :category; ", array(
163
			'key' => $key,
164
			'value' => $value,
165
			'title' => $title,
166
			'description' => $description,
167
			'visible_permissions' => $visible_permissions,
168
			'change_permissions' => $change_permissions,
169
			'owner' => $owner,
170
			'order' => (int) $order,
171
			'icon_path' => $icon_path,
172
			'datatype' => $datatype,
173
			'datatype_params' => $datatype_params,
174
			'editable' => ($editable ? 1 : 0),
175
			'category' => $category,
176
			'activated' => 1
177
		));
178
179
		//update value in local in-memory cache
180
		self::$settings[$key] = $value;
181
182
		//clear cache (area "global_settings")
183
		Cache::clear("global_settings");
184
	}
185
186
	/**
187
	 * delete setting
188
	 */
189
	public static function delete (string $key) {
190
		//remove from in-memory cache
191
		unset(self::$settings[$key]);
192
193
		//remove key in database
194
		Database::getInstance()->execute("DELETE FROM `{praefix}global_settings` WHERE `key` = :key; ", array('key' => $key));
195
196
		//clear cache (area "global_settings")
197
		Cache::clear("global_settings");
198
	}
199
200
	/**
201
	 * initialize settings and get global settings
202
	 */
203
	protected static function loadCategorySettings (string $category) {
204
		//$category = Database::getInstance()->escape($category);
205
206
		$category_settings = array();
207
208
		if (Cache::contains("global_settings", "settings-category-" + $category)) {
209
			$category_settings = Cache::get("global_settings", "settings-category-" + $category);
210
		} else {
211
			//load settings from database
212
			$rows = Database::getInstance()->listRows("SELECT * FROM `{praefix}global_settings` WHERE `category` = :category AND `activated` = '1' ORDER BY `order`; ", array(
213
				'category' => array(
214
					'type' => PDO::PARAM_STR,
215
					'value' => $category
216
				)
217
			));
218
219
			foreach ($rows as $row) {
220
				$category_settings[$row['key']] = $row['value'];
221
			}
222
223
			//cache rows
224
			Cache::put("global_settings", "settings-category-" + $category, $category_settings);
225
		}
226
227
		//merge arrays
228
		self::$settings = array_merge(self::$settings, $category_settings);
229
230
		self::$initialized = true;
231
	}
232
233
	/**
234
	 * initialize settings and get global settings
235
	 */
236
	protected static function loadAllSettings () {
237
		if (Cache::contains("global_settings", "all-settings")) {
238
			self::$settings = Cache::get("global_settings", "all-settings");
239
		} else {
240
			//load settings from database
241
			$rows = Database::getInstance()->listRows("SELECT * FROM `{praefix}global_settings` WHERE `activated` = '1' ORDER BY `order`; ");
242
			
243
			self::$settings = array();
244
245
			foreach ($rows as $row) {
246
				self::$settings[$row['key']] = $row['value'];
247
			}
248
249
			//cache rows
250
			Cache::put("global_settings", "all-settings", self::$settings);
251
		}
252
253
		self::$initialized = true;
254
	}
255
256
	public static function listAllSettingsByCategory () {
257
		//load settings if neccessary
258
		self::loadSettingsIfAbsent();
259
260
		$rows = array();
261
262
		if (Cache::contains("global_settings", "all_rows")) {
263
			$rows = Cache::get("global_settings", "all_rows");
264
		} else {
265
			//load settings from database
266
			$rows = Database::getInstance()->listRows("SELECT * FROM `{praefix}global_settings` WHERE `activated` = '1' ORDER BY `order`; ");
267
268
			Cache::put("global_settings", "all_rows", $rows);
269
		}
270
271
		$list = array();
272
273
		foreach ($rows as $row) {
274
			$category = $row['category'];
275
			$key = $row['key'];
276
277
			//add array, if key doesnt exists in array
278
			if (!isset($list[$category])) {
279
				$list[$category] = array();
280
			}
281
282
			$list[$category][$key] = $row;
283
		}
284
285
		return $list;
286
	}
287
288
	/**
289
	 * load settings, if class was not initialized yet
290
	 */
291
	protected static function loadSettingsIfAbsent () {
292
		if (!self::$initialized) {
293
			self::loadAllSettings();
294
		}
295
	}
296
297
}
298
299
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
300