Completed
Push — master ( 21ecde...d4facc )
by Nazar
04:59
created

Config::init()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 5
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 8
ccs 6
cts 6
cp 1
crap 1
rs 9.4285
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
		Singleton;
26
	const INIT_STATE_METHOD = 'init';
27
	const SYSTEM_MODULE     = 'System';
28
	const SYSTEM_THEME      = 'CleverStyle';
29
	/**
30
	 * @var Cache\Prefix
31
	 */
32
	protected $cache;
33
	/**
34
	 * Most of general configuration properties
35
	 *
36
	 * @var array
37
	 */
38
	public $core = [];
39
	/**
40
	 * @var array
41
	 */
42
	protected $core_internal = [];
43
	/**
44
	 * Configuration of databases, except the main database, parameters of which are stored in configuration file
45
	 *
46
	 * @var mixed[]
47
	 */
48
	public $db = [];
49
	/**
50
	 * Configuration of storages, except the main storage, parameters of which are stored in configuration file
51
	 *
52
	 * @var mixed[]
53
	 */
54
	public $storage = [];
55
	/**
56
	 * Internal structure of components parameters
57
	 *
58
	 * @var array[]
59
	 */
60
	public $components = [];
61
	/**
62
	 * Array of all domains, which allowed to access the site
63
	 *
64
	 * Contains keys:
65
	 * * count - Total count
66
	 * * http - Insecure (http) domains
67
	 * * https - Secure (https) domains
68
	 *
69
	 * @var array
70
	 */
71
	public    $mirrors;
72
	protected $data_model = [
73
		'domain'     => 'text',
74
		'core'       => 'json',
75
		'db'         => 'json',
76
		'storage'    => 'json',
77
		'components' => 'json'
78
	];
79
	protected $table      = '[prefix]config';
80 4
	protected function cdb () {
81 4
		return 0;
82
	}
83 54
	protected function init () {
84 54
		Event::instance()->on(
85 54
			'System/Language/change/after',
86
			function () {
87 44
				$this->read_core_update_multilingual();
88 54
			}
89
		);
90 54
	}
91
	/**
92
	 * Loading of configuration, initialization of $Config, $Cache, $L and Page objects, Routing processing
93
	 *
94
	 * @throws ExitException
95
	 */
96 54
	protected function construct () {
97
		// TODO: Change `config2` to `config` in 6.x
98 54
		$this->cache = Cache::prefix('config2');
99 54
		Event::instance()->fire('System/Config/init/before');
100 54
		$this->load_configuration();
101 54
		date_default_timezone_set($this->core['timezone']);
102 54
		$this->fill_mirrors();
103 54
		Event::instance()->fire('System/Config/init/after');
104 54
		if (!file_exists(MODULES.'/'.$this->core['default_module'])) {
105
			$this->core['default_module'] = self::SYSTEM_MODULE;
106
			$this->save();
107
		}
108 54
	}
109
	/**
110
	 * Is used to fill `$this->mirrors` using current configuration
111
	 */
112 54
	protected function fill_mirrors () {
113 54
		$this->mirrors = [
114
			'count' => 0,
115
			'http'  => [],
116
			'https' => []
117
		];
118 54
		foreach ($this->core['url'] as $i => $address) {
119 54
			list($protocol, $urls) = explode('://', $address, 2);
120 54
			$urls                       = explode(';', $urls);
121 54
			$this->mirrors[$protocol][] = $urls[0];
122
		}
123 54
		$this->mirrors['count'] = count($this->mirrors['http']) + count($this->mirrors['https']);
124 54
	}
125
	/**
126
	 * Reloading of settings cache
127
	 *
128
	 * @throws ExitException
129
	 */
130 54
	protected function load_configuration () {
131
		/**
132
		 * @var array[] $config
133
		 */
134 54
		$config = $this->cache->get(
135 54
			'source',
136
			function () {
137 4
				return $this->read(Core::instance()->domain);
138 54
			}
139
		);
140 54
		if (!$config) {
141 2
			throw new ExitException('Failed to load system configuration', 500);
142
		}
143 54
		$this->core_internal = $config['core'];
144 54
		$this->core          = $this->core_internal;
145 54
		$this->db            = $config['db'];
146 54
		$this->storage       = $config['storage'];
147 54
		$this->components    = $config['components'];
148 54
		$this->core += Options::get_defaults();
149 54
		$this->read_core_update_multilingual();
150 54
		date_default_timezone_set($this->core['timezone']);
151 54
		$this->fill_mirrors();
152 54
	}
153 54
	protected function read_core_update_multilingual () {
154 54
		$language             = Language::instance()->clanguage;
155 54
		$multilingual_options = $this->cache->get(
156
			$language,
157 54
			function () use ($language) {
158 8
				$db_id                = $this->module('System')->db('texts');
159 8
				$Text                 = Text::instance();
160 8
				$multilingual_options = [];
161 8
				foreach (Options::get_multilingual() as $option) {
162 8
					$multilingual_options[$option] = $Text->process($db_id, $this->core_internal[$option], true);
163
				}
164 8
				return $multilingual_options;
165 54
			}
166
		);
167 54
		$this->core           = $multilingual_options + $this->core;
168 54
	}
169
	/**
170
	 * Applying settings without saving changes into db
171
	 *
172
	 * @return bool
173
	 *
174
	 * @throws ExitException
175
	 */
176 2
	public function apply () {
177 2
		$this->core = Options::apply_formatting($this->core) + Options::get_defaults();
178
		/**
179
		 * Update multilingual cache manually to avoid actually storing changes in database
180
		 */
181 2
		$multilingual_options_list = Options::get_multilingual();
182 2
		$multilingual_options      = [];
183 2
		foreach ($this->core as $option => $value) {
184 2
			if (in_array($option, $multilingual_options_list)) {
185 2
				$multilingual_options[$option] = $this->core[$option];
186
			} else {
187 2
				$this->core_internal[$option] = $value;
188
			}
189
		}
190 2
		$this->cache->set(Language::instance()->clanguage, $multilingual_options);
191 2
		return $this->apply_internal();
192
	}
193
	/**
194
	 * Applying settings without saving changes into db
195
	 *
196
	 * @param bool $cache_not_saved_mark
197
	 *
198
	 * @return bool
199
	 *
200
	 * @throws ExitException
201
	 */
202 2
	protected function apply_internal ($cache_not_saved_mark = true) {
203 2
		if ($cache_not_saved_mark) {
204 2
			$this->core_internal['cache_not_saved'] = true;
205
		} else {
206 2
			unset($this->core_internal['cache_not_saved']);
207
		}
208 2
		if (!$this->cache->set(
209 2
			'source',
210
			[
211 2
				'core'       => $this->core_internal,
212 2
				'db'         => $this->db,
213 2
				'storage'    => $this->storage,
214 2
				'components' => $this->components
215
			]
216
		)
217
		) {
218 2
			return false;
219
		}
220 2
		date_default_timezone_set($this->core['timezone']);
221 2
		$this->fill_mirrors();
222 2
		Event::instance()->fire('System/Config/changed');
223 2
		return true;
224
	}
225 2
	protected function write_core_update_multilingual () {
226 2
		$db_id = $this->module('System')->db('texts');
227 2
		$Text  = Text::instance();
228 2
		foreach (Options::get_multilingual() as $option) {
229 2
			$this->core_internal[$option] = $Text->set($db_id, 'System/Config/core', $option, $this->core[$option]);
230
		}
231 2
		$this->cache->del(Language::instance()->clanguage);
232 2
	}
233
	/**
234
	 * Saving settings
235
	 *
236
	 * @return bool
237
	 *
238
	 * @throws ExitException
239
	 */
240 2
	public function save () {
241 2
		unset($this->core_internal['cache_not_saved']);
242
		// TODO: Remove `modules/System/core_settings_defaults.json` file in 6.x
243 2
		$core_settings_defaults = Options::get_defaults();
244 2
		$this->core             = Options::apply_formatting($this->core) + $core_settings_defaults;
245 2
		$this->write_core_update_multilingual();
246 2
		if (!$this->update(Core::instance()->domain, $this->core_internal, $this->db, $this->storage, $this->components)) {
247 2
			return false;
248
		}
249 2
		return $this->apply_internal(false);
250
	}
251
	/**
252
	 * Whether configuration was applied (not saved) and can be canceled
253
	 *
254
	 * @return bool
255
	 */
256
	public function cancel_available () {
257
		return isset($this->core_internal['cache_not_saved']);
258
	}
259
	/**
260
	 * Canceling of applied settings
261
	 *
262
	 * @throws ExitException
263
	 */
264 2
	public function cancel () {
265 2
		$this->cache->del('/');
266 2
		$this->load_configuration();
267 2
	}
268
	/**
269
	 * Get base url of current mirror including language suffix
270
	 *
271
	 * @return string
272
	 */
273 8
	public function base_url () {
274 8
		if (Request::instance()->mirror_index === -1) {
275 2
			return '';
276
		}
277 8
		$base_url = $this->core_url();
278 8
		if ($this->core['multilingual']) {
279 4
			$L = Language::instance();
280 4
			$base_url .= "/$L->clang";
281
		}
282 8
		return $base_url;
283
	}
284
	/**
285
	 * Get base url of main domain
286
	 *
287
	 * @return string
288
	 */
289 14
	public function core_url () {
290 14
		$Request = Request::instance();
291 14
		return "$Request->scheme://$Request->host";
292
	}
293
	/**
294
	 * Get object for getting db and storage configuration of module
295
	 *
296
	 * @param string $module_name
297
	 *
298
	 * @return Config\Module_Properties
299
	 */
300 54
	public function module ($module_name) {
301 54
		if (!isset($this->components['modules'][$module_name])) {
302
			/** @noinspection PhpIncompatibleReturnTypeInspection */
303 2
			return False_class::instance();
304
		}
305 54
		return new Config\Module_Properties($this->components['modules'][$module_name], $module_name);
306
	}
307
}
308