Completed
Push — master ( f134f7...b7128d )
by Nazar
18:27
created

Options   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 307
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 0
loc 307
ccs 114
cts 114
cp 1
rs 8.3396
c 0
b 0
f 0
wmc 44
lcom 1
cbo 1

11 Methods

Rating   Name   Duplication   Size   Complexity  
A get_formatting() 0 9 1
B get_formatting_const() 0 120 1
A get_formatting_const_plain() 0 7 2
A get_languages() 0 12 4
A get_themes() 0 5 2
A get_modules_that_can_be_default() 0 13 4
A get_active_languages() 0 8 2
B get_formatting_normalize() 0 17 8
A get_defaults() 0 9 3
A get_multilingual() 0 10 3
C apply_formatting() 0 48 14

How to fix   Complexity   

Complex Class

Complex classes like Options often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Options, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @package   CleverStyle Framework
4
 * @author    Nazar Mokrynskyi <[email protected]>
5
 * @copyright Copyright (c) 2016, Nazar Mokrynskyi
6
 * @license   MIT License, see license.txt
7
 */
8
namespace cs\Config;
9
use
10
	cs\Config,
11
	cs\DB;
12
13
/**
14
 * Class for getting of db and storage configuration of module
15
 */
16
class Options {
17
	/**
18
	 * Get formats for all supported options
19
	 *
20
	 * Format includes option type, default value, supported values or ranges, whether option is password or is multilingual
21
	 *
22
	 * @return array[]
23
	 */
24 72
	public static function get_formatting () {
25 72
		$formatting                                               = static::get_formatting_const();
26
		$formatting['set_single']['language']['values']           = static::get_active_languages();
27
		$formatting['set_single']['timezone']['values']           = get_timezones_list();
28
		$formatting['set_single']['default_module']['values']     = static::get_modules_that_can_be_default();
29
		$formatting['set_single']['theme']['values']              = static::get_themes();
30 72
		$formatting['set_multiple']['active_languages']['values'] = static::get_languages();
31
		return static::get_formatting_normalize($formatting);
32 60
	}
33 60
	/**
34 60
	 * @return array[]
1 ignored issue
show
Documentation introduced by
Should the return type not be array<string,array>?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
35 60
	 */
36 60
	protected static function get_formatting_const () {
37 60
		return [
38 60
			'array'        => [
39 60
				'url'           => [],
40 60
				'cookie_domain' => []
41 60
			],
42 60
			'int_bool'     => [
43 60
				'site_mode'                         => 1,
44 60
				'title_reverse'                     => 0,
45 60
				'cache_compress_js_css'             => 1,
46 60
				'frontend_load_optimization'        => 1,
47 60
				'vulcanization'                     => 1,
48 60
				'put_js_after_body'                 => 1,
49 60
				'disable_webcomponents'             => 0,
50 60
				'multilingual'                      => 0,
51
				'db_balance'                        => 0,
52
				'db_mirror_mode'                    => DB::MIRROR_MODE_MASTER_MASTER,
53
				'gravatar_support'                  => 0,
54
				'smtp'                              => 0,
55
				'smtp_auth'                         => 0,
56
				'allow_user_registration'           => 1,
57
				'require_registration_confirmation' => 1,
58
				'auto_sign_in_after_registration'   => 1,
59
				'registration_confirmation_time'    => 1,
60
				'remember_user_ip'                  => 0,
61
				'simple_admin_mode'                 => 1
62
			],
63
			'int_range'    => [
64
				'inserts_limit'         => [
65
					'min'   => 1,
66
					'value' => 1000
67
				],
68
				'key_expire'            => [
69
					'min'   => 1,
70
					'value' => 60 * 2
71
				],
72
				'session_expire'        => [
73
					'min'   => 1,
74
					'value' => 3600 * 24 * 30
75
				],
76
				'update_ratio'          => [
77
					'min'   => 0,
78
					'max'   => 100,
79
					'value' => 75
80
				],
81
				'password_min_length'   => [
82
					'min'   => 1,
83
					'value' => 4
84
				],
85
				'password_min_strength' => [
86 72
					'min'   => 0,
87 72
					'max'   => 7,
88 72
					'value' => 3
89
				]
90
			],
91 72
			'set_single'   => [
92 72
				'smtp_secure'    => [
93
					'value'  => '',
94
					'values' => ['', 'ssl', 'tls']
95
				],
96 72
				'language'       => [
97
					'value'  => 'English',
98
					'source' => 'active_languages'
99
				],
100 72
				'timezone'       => [
101
					'value' => 'UTC'
102
				],
103
				'default_module' => [
104
					'value' => Config::SYSTEM_MODULE
105
				],
106
				'theme'          => [
107
					'value' => Config::SYSTEM_THEME
108 72
				]
109
			],
110
			'set_multiple' => [
111
				'active_languages' => [
112
					'value' => [
113
						'English'
114
					]
115
				]
116
			],
117
			'string'       => [
118
				'admin_email'   => '',
119
				'cookie_prefix' => '',
120
				'smtp_host'     => '',
121
				'smtp_port'     => '',
122
				'smtp_user'     => '',
123
				'smtp_password' => [
124
					'value'    => '',
125
					'password' => true
126
				],
127
				'mail_from'     => ''
128
			],
129
			'text'         => [
130
				'title_delimiter' => ' | ',
131
				'site_name'       => [
132
					'multilingual' => true,
133
					'value'        => ''
134
				],
135
				'closed_title'    => [
136
					'multilingual' => true,
137
					'value'        => 'Site closed'
138
				],
139
				'mail_from_name'  => [
140
					'multilingual' => true,
141
					'value'        => 'Administrator'
142
				]
143
			],
144
			'html'         => [
145
				'closed_text'    => [
146
					'multilingual' => true,
147
					'value'        => '<p>Site closed for maintenance</p>'
148
				],
149
				'mail_signature' => [
150
					'multilingual' => true,
151
					'value'        => ''
152
				]
153
			]
154 72
		];
155 72
	}
156 72
	/**
157
	 * @return array[]
158 72
	 */
159 72
	protected static function get_formatting_const_plain () {
160
		static $formatting;
161
		if (!isset($formatting)) {
162 72
			$formatting = array_merge(...array_values(static::get_formatting_const()));
163 72
		}
164 72
		return $formatting;
165
	}
166
	/**
167
	 * @return string[]
168
	 */
169 72
	protected static function get_languages () {
170 72
		$languages = defined('LANGUAGES')
171 72
			? array_unique(
172 72
				array_merge(
173
					_mb_substr(get_files_list(LANGUAGES, '/^.*?\.php$/i', 'f'), 0, -4) ?: [],
174
					_mb_substr(get_files_list(LANGUAGES, '/^.*?\.json$/i', 'f'), 0, -5) ?: []
175
				)
176
			)
177 72
			: ['English'];
178 72
		asort($languages);
179 72
		return $languages;
180 72
	}
181
	/**
182
	 * @return string[]
183 12
	 */
184 12
	protected static function get_themes () {
185
		$themes = defined('THEMES') ? get_files_list(THEMES, false, 'd') : [Config::SYSTEM_THEME];
186 12
		asort($themes);
187 12
		return $themes;
188
	}
189
	/**
190
	 * @return string[]
191
	 */
192
	protected static function get_modules_that_can_be_default () {
193 72
		$Config = Config::instance(true);
194 72
		if (!defined('MODULES') || !isset($Config->components['modules'])) {
195 72
			return [Config::SYSTEM_MODULE];
196 72
		}
197
		/** @noinspection PhpParamsInspection */
198
		return array_filter(
199 12
			array_keys($Config->components['modules']),
200
			function ($module) use ($Config) {
201
				return $Config->module($module) && file_exists_with_extension(MODULES."/$module/index", ['php', 'html', 'json']);
202
			}
203
		);
204
	}
205
	/**
206 72
	 * @return string[]
207 72
	 */
208 72
	protected static function get_active_languages () {
209 72
		$Config = Config::instance(true);
210
		if (!isset($Config->core['active_languages'])) {
211 72
			return ['English'];
212
		}
213
		/** @noinspection PhpIncompatibleReturnTypeInspection */
214 72
		return $Config->core['active_languages'];
215 72
	}
216 72
	/**
217
	 * @param array[] $format
218
	 *
219 72
	 * @return array[]
220
	 */
221 72
	protected static function get_formatting_normalize ($format) {
222
		foreach ($format as $type => &$items) {
223
			foreach ($items as $item => &$data) {
224
				if (!is_array($data) || !isset($data['value'])) {
225
					$data = [
226
						'value' => $data
227
					];
228 72
				}
229 72
				$data['type'] = $type;
230
				if (($type == 'set_single' || $type == 'set_multiple') && !is_array_assoc($data['values'])) {
231 72
					$data['values'] = array_combine($data['values'], $data['values']);
232 72
				}
233 72
			}
234
			unset($data);
235
		}
236
		return array_merge(...array_values($format));
237
	}
238
	/**
239
	 * Get default values for all supported options
240
	 *
241 12
	 * @return array
1 ignored issue
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
242 12
	 */
243
	public static function get_defaults () {
244
		$formatting = static::get_formatting_const_plain();
245 12
		foreach ($formatting as &$f) {
246
			if (isset($f['value'])) {
247 12
				$f = $f['value'];
248 12
			}
249
		}
250
		return $formatting;
251
	}
252
	/**
253
	 * Get list of multilingual options
254
	 *
255
	 * @return string[]
256
	 */
257
	public static function get_multilingual () {
258
		$formatting = static::get_formatting_const_plain();
259
		$result     = [];
260 4
		foreach ($formatting as $key => $f) {
261 4
			if (isset($f['multilingual'])) {
262 4
				$result[] = $key;
263 4
			}
264 2
		}
265
		return $result;
266 4
	}
267 4
	/**
268 4
	 * Take options and check each value according to needed format, correct value or use default if needed
269 4
	 *
270 4
	 * @param array $target_options
271 4
	 *
272 4
	 * @return array
273 4
	 */
274 4
	public static function apply_formatting ($target_options) {
275 4
		$options = static::get_formatting();
276 4
		foreach ($target_options as $option => &$value) {
277
			if (!isset($options[$option])) {
278 4
				unset($target_options[$option]);
279 4
			} else {
280
				$format = $options[$option];
281 4
				switch ($format['type']) {
282 4
					case 'array':
283 4
						$value = xap((array)$value);
284 4
						break;
285 2
					case 'int_bool':
286
						$value = (int)(bool)$value;
287 4
						break;
288 4
					case 'int_range':
289 4
						if (isset($format['min'])) {
290 4
							$value = max($format['min'], (int)$value);
291 4
						}
292 4
						if (isset($format['max'])) {
293 4
							$value = min($format['max'], (int)$value);
294
						}
295 4
						break;
296 4
					case 'set_single':
297 4
						$value = (string)$value;
298 4
						if (!in_array($value, $format['values'], true)) {
299 4
							$value = $format['value'];
300 4
						}
301 4
						break;
302 4
					case 'set_multiple':
303
						$value = array_filter(
304
							(array)$value,
305
							function ($value) use ($format) {
306 4
								return in_array((string)$value, $format['values'], true);
307
							}
308
						);
309
						$value = $value ?: [$format['value']];
310
						break;
311
					case 'text':
312
						$value = xap($value);
313
						break;
314
					case 'html':
315
						$value = xap($value, true);
316
						break;
317
				}
318
			}
319
		}
320
		return $target_options;
321
	}
322
}
323