Completed
Push — master ( 674f63...1322e1 )
by Nazar
04:59
created

Config   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 312
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 14

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 0
loc 312
ccs 120
cts 120
cp 1
rs 9.6
c 0
b 0
f 0
wmc 32
lcom 1
cbo 14

15 Methods

Rating   Name   Duplication   Size   Complexity  
A cdb() 0 3 1
A init() 0 9 1
A construct() 0 11 2
A load_configuration() 0 22 2
A fill_mirrors() 0 13 2
B read_core_update_multilingual() 0 20 5
A core() 0 3 1
A apply() 0 17 3
A apply_internal() 0 23 3
B save() 0 24 4
A cancel_available() 0 3 1
A cancel() 0 4 1
A base_url() 0 11 3
A core_url() 0 4 1
A module() 0 7 2
1
<?php
2
/**
3
 * @package   CleverStyle Framework
4
 * @author    Nazar Mokrynskyi <[email protected]>
5
 * @copyright Copyright (c) 2011-2016, Nazar Mokrynskyi
6
 * @license   MIT License, see license.txt
7
 */
8
namespace cs;
9
use
10
	cs\Config\Options;
11
12
/**
13
 * Provides next events:
14
 *  System/Config/init/before
15
 *
16
 *  System/Config/init/after
17
 *
18
 *  System/Config/changed
19
 *
20
 * @method static $this instance($check = false)
21
 */
22
class Config {
23
	use
24
		CRUD,
25
		Properties_getter,
26
		Singleton;
27
	const INIT_STATE_METHOD = 'init';
28
	const SYSTEM_MODULE     = 'System';
29
	const SYSTEM_THEME      = 'CleverStyle';
30
	/**
31
	 * @var Cache\Prefix
32
	 */
33
	protected $cache;
34
	/**
35
	 * Most of general configuration properties
36
	 *
37
	 * @var array
38
	 */
39
	public $core = [];
40
	/**
41
	 * @var array
42
	 */
43
	protected $core_internal = [];
44
	/**
45
	 * @var string
46
	 */
47
	protected $last_language;
48
	/**
49
	 * Configuration of databases, except the main database, parameters of which are stored in configuration file
50
	 *
51
	 * @var mixed[]
52
	 */
53
	public $db = [];
54
	/**
55
	 * Configuration of storages, except the main storage, parameters of which are stored in configuration file
56
	 *
57
	 * @var mixed[]
58
	 */
59
	public $storage = [];
60
	/**
61
	 * Internal structure of components parameters
62
	 *
63
	 * @var array[]
64
	 */
65
	public $components = [];
66
	/**
67
	 * Array of all domains, which allowed to access the site
68
	 *
69
	 * Contains keys:
70
	 * * count - Total count
71
	 * * http - Insecure (http) domains
72
	 * * https - Secure (https) domains
73
	 *
74
	 * @var array
75
	 */
76
	public    $mirrors;
77
	protected $data_model = [
78
		'domain'     => 'text',
79
		'core'       => 'json',
80
		'db'         => 'json',
81
		'storage'    => 'json',
82
		'components' => 'json'
83
	];
84
	protected $table      = '[prefix]config';
85 4
	protected function cdb () {
86 4
		return 0;
87
	}
88
	/**
89
	 * Update multilingual options when language changes
90
	 */
91 54
	protected function init () {
92 54
		$this->read_core_update_multilingual();
93 54
		Event::instance()->on(
94 54
			'System/Language/change/after',
95
			function () {
96 44
				$this->read_core_update_multilingual();
97 54
			}
98
		);
99 54
	}
100
	/**
101
	 * Loading of configuration, initialization of $Config, $Cache, $L and Page objects, Routing processing
102
	 *
103
	 * @throws ExitException
104
	 */
105 54
	protected function construct () {
106
		// TODO: Change `config2` to `config` in 6.x
107 54
		$this->cache = Cache::prefix('config2');
108 54
		Event::instance()->fire('System/Config/init/before');
109 54
		$this->load_configuration();
110 54
		Event::instance()->fire('System/Config/init/after');
111 54
		if (!file_exists(MODULES.'/'.$this->core['default_module'])) {
112 2
			$this->core['default_module'] = self::SYSTEM_MODULE;
113 2
			$this->save();
114
		}
115 54
	}
116
	/**
117
	 * Reloading of settings cache
118
	 *
119
	 * @throws ExitException
120
	 */
121 54
	protected function load_configuration () {
122
		/**
123
		 * @var array[] $config
124
		 */
125 54
		$config = $this->cache->get(
126 54
			'source',
127
			function () {
128 4
				return $this->read(Core::instance()->domain);
129 54
			}
130
		);
131 54
		if (!$config) {
132 2
			throw new ExitException('Failed to load system configuration', 500);
133
		}
134 54
		$this->core_internal = $config['core'];
135 54
		$this->core          = $this->core_internal;
136 54
		$this->db            = $config['db'];
137 54
		$this->storage       = $config['storage'];
138 54
		$this->components    = $config['components'];
139 54
		$this->core += Options::get_defaults();
140 54
		date_default_timezone_set($this->core['timezone']);
141 54
		$this->fill_mirrors();
142 54
	}
143
	/**
144
	 * Is used to fill `$this->mirrors` using current configuration
145
	 */
146 54
	protected function fill_mirrors () {
147 54
		$this->mirrors = [
148
			'count' => 0,
149
			'http'  => [],
150
			'https' => []
151
		];
152 54
		foreach ($this->core['url'] as $i => $address) {
153 54
			list($protocol, $urls) = explode('://', $address, 2);
154 54
			$urls                       = explode(';', $urls);
155 54
			$this->mirrors[$protocol][] = $urls[0];
156
		}
157 54
		$this->mirrors['count'] = count($this->mirrors['http']) + count($this->mirrors['https']);
158 54
	}
159 54
	protected function read_core_update_multilingual () {
160 54
		$language = Language::instance(true)->clanguage ?: @$this->core['language'];
161 54
		if (!$language || $language == $this->last_language) {
162 48
			return;
163
		}
164 52
		$this->last_language  = $language;
165 52
		$multilingual_options = $this->cache->get(
166
			$language,
167 52
			function () {
168 8
				$db_id                = $this->module('System')->db('texts');
169 8
				$Text                 = Text::instance();
170 8
				$multilingual_options = [];
171 8
				foreach (Options::get_multilingual() as $option) {
172 8
					$multilingual_options[$option] = $Text->process($db_id, $this->core_internal[$option], true);
173
				}
174 8
				return $multilingual_options;
175 52
			}
176
		);
177 52
		$this->core           = $multilingual_options + $this->core;
178 52
	}
179
	/**
180
	 * Get core options item
181
	 *
182
	 * @param string[]|string[][] $item
183
	 *
184
	 * @return mixed|mixed[]|null Core options items (or associative array of items) if exists or `null` otherwise (in case if `$item` is an array even one
185
	 *                            missing key will cause the whole thing to fail)
186
	 */
187 2
	public function core (...$item) {
188 2
		return $this->get_property_items('core', $item);
1 ignored issue
show
Documentation introduced by
$item is of type array<integer,array<inte...array<integer,string>>>, but the function expects a array<integer,string|array<integer,string>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
189
	}
190
	/**
191
	 * Applying settings without saving changes into db
192
	 *
193
	 * @return bool
194
	 *
195
	 * @throws ExitException
196
	 */
197 2
	public function apply () {
198 2
		$this->core = Options::apply_formatting($this->core) + Options::get_defaults();
199
		/**
200
		 * Update multilingual cache manually to avoid actually storing changes in database
201
		 */
202 2
		$multilingual_options_list = Options::get_multilingual();
203 2
		$multilingual_options      = [];
204 2
		foreach ($this->core as $option => $value) {
205 2
			if (in_array($option, $multilingual_options_list)) {
206 2
				$multilingual_options[$option] = $this->core[$option];
207
			} else {
208 2
				$this->core_internal[$option] = $value;
209
			}
210
		}
211 2
		$this->cache->set(Language::instance()->clanguage, $multilingual_options);
212 2
		return $this->apply_internal();
213
	}
214
	/**
215
	 * Applying settings without saving changes into db
216
	 *
217
	 * @param bool $cache_not_saved_mark
218
	 *
219
	 * @return bool
220
	 *
221
	 * @throws ExitException
222
	 */
223 2
	protected function apply_internal ($cache_not_saved_mark = true) {
224 2
		if ($cache_not_saved_mark) {
225 2
			$this->core_internal['cache_not_saved'] = true;
226
		} else {
227 2
			unset($this->core_internal['cache_not_saved']);
228
		}
229 2
		if (!$this->cache->set(
230 2
			'source',
231
			[
232 2
				'core'       => $this->core_internal,
233 2
				'db'         => $this->db,
234 2
				'storage'    => $this->storage,
235 2
				'components' => $this->components
236
			]
237
		)
238
		) {
239 2
			return false;
240
		}
241 2
		date_default_timezone_set($this->core['timezone']);
242 2
		$this->fill_mirrors();
243 2
		Event::instance()->fire('System/Config/changed');
244 2
		return true;
245
	}
246
	/**
247
	 * Saving settings
248
	 *
249
	 * @return bool
250
	 *
251
	 * @throws ExitException
252
	 */
253 2
	public function save () {
254 2
		unset($this->core_internal['cache_not_saved']);
255
		// TODO: Remove `modules/System/core_settings_defaults.json` file in 6.x
256 2
		$core_settings_defaults = Options::get_defaults();
257 2
		$this->core             = Options::apply_formatting($this->core) + $core_settings_defaults;
258
259
		/**
260
		 * Persist multilingual options and copy the rest to `$this->core_internal` as is
261
		 */
262 2
		$multilingual_options_list = Options::get_multilingual();
263 2
		$db_id                     = $this->module('System')->db('texts');
264 2
		$Text                      = Text::instance();
265 2
		foreach ($this->core as $option => $value) {
266 2
			if (in_array($option, $multilingual_options_list)) {
267 2
				$this->core_internal[$option] = $Text->set($db_id, 'System/Config/core', $option, $this->core[$option]);
268
			} else {
269 2
				$this->core_internal[$option] = $value;
270
			}
271
		}
272 2
		if (!$this->update(Core::instance()->domain, $this->core_internal, $this->db, $this->storage, $this->components)) {
273 2
			return false;
274
		}
275 2
		return $this->apply_internal(false);
276
	}
277
	/**
278
	 * Whether configuration was applied (not saved) and can be canceled
279
	 *
280
	 * @return bool
281
	 */
282 2
	public function cancel_available () {
283 2
		return isset($this->core_internal['cache_not_saved']);
284
	}
285
	/**
286
	 * Canceling of applied settings
287
	 *
288
	 * @throws ExitException
289
	 */
290 2
	public function cancel () {
291 2
		$this->cache->del('/');
292 2
		$this->load_configuration();
293 2
	}
294
	/**
295
	 * Get base url of current mirror including language suffix
296
	 *
297
	 * @return string
298
	 */
299 8
	public function base_url () {
300 8
		if (Request::instance()->mirror_index === -1) {
301 2
			return '';
302
		}
303 8
		$base_url = $this->core_url();
304 8
		if ($this->core['multilingual']) {
305 4
			$L = Language::instance();
306 4
			$base_url .= "/$L->clang";
307
		}
308 8
		return $base_url;
309
	}
310
	/**
311
	 * Get base url of main domain
312
	 *
313
	 * @return string
314
	 */
315 14
	public function core_url () {
316 14
		$Request = Request::instance();
317 14
		return "$Request->scheme://$Request->host";
318
	}
319
	/**
320
	 * Get object for getting db and storage configuration of module
321
	 *
322
	 * @param string $module_name
323
	 *
324
	 * @return Config\Module_Properties
325
	 */
326 54
	public function module ($module_name) {
327 54
		if (!isset($this->components['modules'][$module_name])) {
328
			/** @noinspection PhpIncompatibleReturnTypeInspection */
329 2
			return False_class::instance();
330
		}
331 54
		return new Config\Module_Properties($this->components['modules'][$module_name], $module_name);
332
	}
333
}
334