Completed
Push — master ( 04c2f3...b80779 )
by Nazar
04:15
created

Config::apply()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * @package   CleverStyle CMS
4
 * @author    Nazar Mokrynskyi <[email protected]>
5
 * @copyright Copyright (c) 2011-2015, Nazar Mokrynskyi
6
 * @license   MIT License, see license.txt
7
 */
8
namespace cs;
9
10
/**
11
 * Provides next events:
12
 *  System/Config/init/before
13
 *
14
 *  System/Config/init/after
15
 *
16
 * @method static Config instance($check = false)
17
 */
18
class Config {
19
	use
20
		Singleton;
21
	const SYSTEM_MODULE = 'System';
22
	const SYSTEM_THEME  = 'CleverStyle';
23
	/**
24
	 * Most of general configuration properties
25
	 *
26
	 * @var mixed[]
27
	 */
28
	public $core = [];
29
	/**
30
	 * Configuration of databases, except the main database, parameters of which are stored in configuration file
31
	 *
32
	 * @var mixed[]
33
	 */
34
	public $db = [];
35
	/**
36
	 * Configuration of storages, except the main storage, parameters of which are stored in configuration file
37
	 *
38
	 * @var mixed[]
39
	 */
40
	public $storage = [];
41
	/**
42
	 * Internal structure of components parameters
43
	 *
44
	 * @var mixed[]
45
	 */
46
	public $components = [];
47
	/**
48
	 * Array of all domains, which allowed to access the site
49
	 *
50
	 * Contains keys:
51
	 * * count - Total count
52
	 * * http - Insecure (http) domains
53
	 * * https - Secure (https) domains
54
	 *
55
	 * @var array
56
	 */
57
	public $mirrors = [
58
		'count' => 0,
59
		'http'  => [],
60
		'https' => []
61
	];
62
	/**
63
	 * Loading of configuration, initialization of $Config, $Cache, $L and Page objects, Routing processing
64
	 *
65
	 * @throws ExitException
66
	 */
67
	protected function construct () {
68
		/**
69
		 * Reading settings from cache and defining missing data
70
		 */
71
		$config = Cache::instance()->config;
72
		/**
73
		 * Cache reloading, if necessary
74
		 */
75
		if (!is_array($config)) {
76
			$this->load_config_from_db();
77
		} else {
78
			foreach ($config as $part => $value) {
79
				$this->$part = $value;
80
			}
81
			unset($part, $value);
82
		}
83
		Event::instance()->fire('System/Config/init/before');
84
		/**
85
		 * System initialization with current configuration
86
		 */
87
		$this->init();
88
		Event::instance()->fire('System/Config/init/after');
89
		if (!file_exists(MODULES.'/'.$this->core['default_module'])) {
90
			$this->core['default_module'] = self::SYSTEM_MODULE;
91
			$this->save();
92
		}
93
	}
94
	/**
95
	 * Engine initialization (or reinitialization if necessary)
96
	 *
97
	 * @throws ExitException
98
	 */
99
	protected function init () {
100
		Language::instance()->init();
101
		$Page = Page::instance();
102
		$Page->init(
103
			get_core_ml_text('name'),
104
			$this->core['theme']
105
		);
106
		/**
107
		 * Setting system timezone
108
		 */
109
		date_default_timezone_set($this->core['timezone']);
110
		$this->fill_mirrors();
111
	}
112
	/**
113
	 * Is used to fill `$this->mirrors` using current configuration
114
	 */
115
	protected function fill_mirrors () {
116
		foreach ($this->core['url'] as $i => $address) {
117
			list($protocol, $urls) = explode('://', $address, 2);
118
			$urls                       = explode(';', $urls);
119
			$this->mirrors[$protocol][] = $urls[0];
120
		}
121
		$this->mirrors['count'] = count($this->mirrors['http']) + count($this->mirrors['https']);
122
	}
123
	/**
124
	 * Reloading of settings cache
125
	 *
126
	 * @return bool
127
	 *
128
	 * @throws ExitException
129
	 */
130
	protected function load_config_from_db () {
131
		$result = DB::instance()->qf(
1 ignored issue
show
Documentation Bug introduced by
The method qf does not exist on object<cs\DB>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
132
			[
133
				"SELECT
134
					`core`,
135
					`db`,
136
					`storage`,
137
					`components`
138
				FROM `[prefix]config`
139
				WHERE `domain` = '%s'
140
				LIMIT 1",
141
				DOMAIN
142
			]
143
		);
144
		if (is_array($result)) {
145
			foreach ($result as $part => $value) {
146
				$this->$part = _json_decode($value);
147
			}
148
			unset($part, $value);
149
		} else {
150
			return false;
151
		}
152
		$this->apply_internal(false);
153
		return true;
154
	}
155
	/**
156
	 * Applying settings without saving changes into db
157
	 *
158
	 * @return bool
159
	 *
160
	 * @throws ExitException
161
	 */
162
	function apply () {
163
		return $this->apply_internal();
164
	}
165
	/**
166
	 * Applying settings without saving changes into db
167
	 *
168
	 * @param bool $cache_not_saved_mark
169
	 *
170
	 * @return bool
171
	 *
172
	 * @throws ExitException
173
	 */
174
	protected function apply_internal ($cache_not_saved_mark = true) {
175
		if ($cache_not_saved_mark) {
176
			$this->core['cache_not_saved'] = true;
177
		} else {
178
			unset($this->core['cache_not_saved']);
179
		}
180
		$Cache = Cache::instance();
181
		if (!$Cache->set(
182
			'config',
183
			[
184
				'core'       => $this->core,
185
				'db'         => $this->db,
186
				'storage'    => $this->storage,
187
				'components' => $this->components
188
			]
189
		)
190
		) {
191
			return false;
192
		}
193
		unset($Cache->{'languages'});
194
		$L = Language::instance();
195
		if ($this->core['multilingual'] && User::instance(true)) {
196
			$L->change(User::instance()->language);
197
		} else {
198
			$L->change($this->core['language']);
199
		}
200
		$this->init();
201
		return true;
202
	}
203
	/**
204
	 * Saving settings
205
	 *
206
	 * @return bool
207
	 *
208
	 * @throws ExitException
209
	 */
210
	function save () {
211
		if ($this->cancel_available()) {
212
			unset($this->core['cache_not_saved']);
213
		}
214
		$core_settings_keys = file_get_json(MODULES.'/System/core_settings_keys.json');
215
		foreach ($this->core as $key => $value) {
216
			if (!in_array($key, $core_settings_keys)) {
217
				unset($this->core[$key]);
218
			}
219
		}
220
		if (DB::instance()->db_prime(0)->q(
221
			"UPDATE `[prefix]config`
222
			SET
223
				`core`			= '%s',
224
				`db`			= '%s',
225
				`storage`		= '%s',
226
				`components`	= '%s'
227
			WHERE `domain` = '%s'
228
			LIMIT 1",
229
			_json_encode($this->core),
230
			_json_encode($this->db),
231
			_json_encode($this->storage),
232
			_json_encode($this->components),
233
			DOMAIN
234
		)
235
		) {
236
			$this->apply_internal(false);
237
			return true;
238
		}
239
		return false;
240
	}
241
	/**
242
	 * Whether configuration was applied (not saved) and can be canceled
243
	 *
244
	 * @return bool
245
	 */
246
	function cancel_available () {
247
		return isset($this->core['cache_not_saved']);
248
	}
249
	/**
250
	 * Canceling of applied settings
251
	 *
252
	 * @return bool
253
	 *
254
	 * @throws ExitException
255
	 */
256
	function cancel () {
257
		return $this->load_config_from_db() && $this->apply_internal(false);
258
	}
259
	/**
260
	 * Get base url of current mirror including language suffix
261
	 *
262
	 * @return string
263
	 */
264
	function base_url () {
265
		if (Route::instance()->mirror_index === -1) {
266
			return '';
267
		}
268
		/**
269
		 * @var _SERVER $_SERVER
270
		 */
271
		$base_url = "$_SERVER->protocol://$_SERVER->host";
272
		$L        = Language::instance();
273
		if ($L->url_language()) {
274
			$base_url .= "/$L->clang";
275
		}
276
		return $base_url;
277
	}
278
	/**
279
	 * Get base url of main domain
280
	 *
281
	 * @return string
282
	 */
283
	function core_url () {
284
		/**
285
		 * @var _SERVER $_SERVER
286
		 */
287
		return "$_SERVER->protocol://$_SERVER->host";
288
	}
289
	/**
290
	 * Get object for getting db and storage configuration of module
291
	 *
292
	 * @param string $module_name
293
	 *
294
	 * @return Config\Module_Properties
295
	 */
296
	function module ($module_name) {
297
		if (!isset($this->components['modules'][$module_name])) {
298
			return False_class::instance();
299
		}
300
		return new Config\Module_Properties($this->components['modules'][$module_name], $module_name);
301
	}
302
}
303