Installer::initialize_system_config()   B
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 45
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 3.0198

Importance

Changes 0
Metric Value
cc 3
eloc 36
nc 4
nop 9
dl 0
loc 45
rs 8.8571
c 0
b 0
f 0
ccs 20
cts 23
cp 0.8696
crap 3.0198

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * @package    CleverStyle Framework
4
 * @subpackage Installer
5
 * @author     Nazar Mokrynskyi <[email protected]>
6
 * @license    0BSD
7
 */
8
namespace cs;
9
use
10
	RuntimeException;
11
12
class Installer {
13
	const MAIN_CONFIG_STUB = /** @lang JSON */
14
		<<<CONFIG
15
{
16
//Domain of main mirror
17
	"domain"			: "@domain",
18
//Base timezone
19
	"timezone"			: "@timezone",
20
//Settings of main DB
21
	"db_host"			: "@db_host",
22
	"db_driver"			: "@db_driver",
23
	"db_name"			: "@db_name",
24
	"db_user"			: "@db_user",
25
	"db_password"		: "@db_password",
26
	"db_prefix"			: "@db_prefix",
27
//Settings of main Storage
28
	"storage_driver"		: "Local",
29
	"storage_url"		: "",
30
	"storage_host"		: "localhost",
31
	"storage_user"		: "",
32
	"storage_password"	: "",
33
//Base language
34
	"language"			: "@language",
35
//Cache driver
36
	"cache_driver"		: "FileSystem",
37
//Settings of Memcached cache driver
38
	"memcache_host"		: "127.0.0.1",
39
	"memcache_port"		: "11211",
40
//Any length
41
	"public_key"		: "@public_key"
42
}
43
44
CONFIG;
45
	/**
46
	 * @param string $source
47
	 * @param string $target
48
	 * @param string $site_name
49
	 * @param string $url
50
	 * @param string $timezone
51
	 * @param string $db_host
52
	 * @param string $db_driver
53
	 * @param string $db_name
54
	 * @param string $db_user
55
	 * @param string $db_password
56
	 * @param string $db_prefix
57
	 * @param string $language
58
	 * @param string $admin_email
59
	 * @param string $admin_password
60
	 * @param int    $mode
61
	 *
62
	 * @throws RuntimeException
63
	 */
64 5
	public static function install (
65
		$source,
66
		$target,
67
		$site_name,
68
		$url,
69
		$timezone,
70
		$db_host,
71
		$db_driver,
72
		$db_name,
73
		$db_user,
74
		$db_password,
75
		$db_prefix,
76
		$language,
77
		$admin_email,
78
		$admin_password,
79
		$mode
80
	) {
81 5
		static::pre_installation_checks($source, $target, $db_driver);
82 5
		$file_index_map = static::initialize_filesystem($source);
83 5
		static::extract($file_index_map, $source, $target);
84 5
		$domain     = explode('/', $url)[2];
85 5
		$public_key = hash('sha512', random_bytes(1000));
86 5
		static::initialize_core_config(
87 5
			$target,
88 5
			$domain,
89 5
			$timezone,
90 5
			$db_host,
91 5
			$db_driver,
92 5
			$db_name,
93 5
			$db_user,
94 5
			$db_password,
95 5
			$db_prefix,
96 5
			$language,
97 5
			$public_key
98
		);
99
		/**
100
		 * @var \cs\DB\_Abstract $cdb
101
		 */
102 5
		$cdb = "cs\\DB\\$db_driver";
103 5
		$cdb = new $cdb($db_name, $db_user, $db_password, $db_host, $db_prefix);
104 5
		if (!is_object($cdb) || !$cdb->connected()) {
105
			throw new RuntimeException("Can't connect to database! Installation aborted.");
106
		}
107 5
		static::initialize_db_structure($cdb, $source, $db_driver);
108 5
		static::initialize_system_config($cdb, $source, $site_name, $url, $admin_email, $language, $domain, $timezone, $mode);
109 5
		static::create_root_administrator($cdb, $admin_email, $admin_password, $public_key);
110 5
		unset($cdb);
111 5
	}
112
	/**
113
	 * @param string $source
114
	 * @param string $target
115
	 * @param string $db_driver
116
	 *
117
	 * @throws RuntimeException
118
	 */
119 5
	protected static function pre_installation_checks ($source, $target, $db_driver) {
120 5
		if (file_exists("$target/config/main.json")) {
121
			throw new RuntimeException('"config/main.json" file already present! Installation aborted.');
122
		}
123 5
		if (!file_exists("$source/DB/$db_driver.sql")) {
124
			throw new RuntimeException("Can't find system tables structure for selected database driver! Installation aborted.");
125
		}
126 5
	}
127
	/**
128
	 * @param string $source
129
	 *
130
	 * @return array[]
131
	 */
132 5
	protected static function initialize_filesystem ($source) {
133 5
		$file_index_map = json_decode(file_get_contents("$source/fs_installer.json"), true);
134 5
		require_once "$source/fs/".$file_index_map['core/thirdparty/upf.php'];
135 5
		require_once "$source/fs/".$file_index_map['core/functions.php'];
136
		// Remove default autoloader, since we have special autoloader suitable for operating inside installer where default will fail hard
137 5
		spl_autoload_unregister(array_reverse(spl_autoload_functions())[0]);
138
		/**
139
		 * Special autoloader for installer
140
		 */
141 5
		spl_autoload_register(
142 5
			function ($class) use ($file_index_map, $source) {
143 5
				$prepared_class_name = ltrim($class, '\\');
144 5
				if (strpos($prepared_class_name, 'cs\\') === 0) {
145 5
					$prepared_class_name = substr($prepared_class_name, 3);
146
				}
147 5
				$prepared_class_name = explode('\\', $prepared_class_name);
148 5
				$namespace           = count($prepared_class_name) > 1 ? implode('/', array_slice($prepared_class_name, 0, -1)) : '';
149 5
				$class_name          = array_pop($prepared_class_name);
150
				/**
151
				 * Try to load classes from different places. If not found in one place - try in another.
152
				 */
153
				if (
154 5
					strlen($file = @$file_index_map[str_replace('//', '/', "core/classes/$namespace/$class_name.php")]) ||    //Core classes
155 5
					strlen($file = @$file_index_map[str_replace('//', '/', "core/thirdparty/$namespace/$class_name.php")]) || //Third party classes
156 5
					strlen($file = @$file_index_map[str_replace('//', '/', "core/traits/$namespace/$class_name.php")]) ||     //Core traits
157 5
					strlen($file = @$file_index_map[str_replace('//', '/', "core/drivers/$namespace/$class_name.php")]) ||    //Core drivers
158 5
					strlen($file = @$file_index_map[str_replace('//', '/', "$namespace/$class_name.php")])                    //Classes in modules
159
				) {
160 5
					require_once "$source/fs/$file";
161 5
					return true;
162
				}
163
				return false;
164 5
			}
165
		);
166 5
		return $file_index_map;
167
	}
168
	/**
169
	 * @param array[] $file_index_map
170
	 * @param string  $source
171
	 * @param string  $target
172
	 *
173
	 * @throws RuntimeException
174
	 */
175 5
	protected static function extract ($file_index_map, $source, $target) {
176
		/**
177
		 * Extracting of system files
178
		 */
179 5
		foreach ($file_index_map as $file_path => $file_index) {
180 5
			$dir = dirname("$target/$file_path");
181 5
			if (!@mkdir($dir, 0770, true) && !is_dir($dir)) {
182
				throw new RuntimeException("Can't extract system files from the archive, creating directory $dir failed! Installation aborted.");
183
			}
184 5
			if (!copy("$source/fs/$file_index", "$target/$file_path")) {
185 5
				throw new RuntimeException("Can't extract system files from the archive, creating file $target/$file_path failed! Installation aborted.");
186
			}
187
		}
188 5
		file_put_json("$target/core/fs.json", array_keys(file_get_json("$source/fs.json")));
189
		/**
190
		 * Make CLI executable
191
		 */
192 5
		chmod("$target/cli", 0770);
193 5
	}
194
	/**
195
	 * @param string $target
196
	 * @param string $domain
197
	 * @param string $timezone
198
	 * @param string $db_host
199
	 * @param string $db_driver
200
	 * @param string $db_name
201
	 * @param string $db_user
202
	 * @param string $db_password
203
	 * @param string $db_prefix
204
	 * @param string $language
205
	 * @param string $public_key
206
	 *
207
	 * @throws RuntimeException
208
	 */
209 5
	protected static function initialize_core_config (
210
		$target,
211
		$domain,
212
		$timezone,
213
		$db_host,
214
		$db_driver,
215
		$db_name,
216
		$db_user,
217
		$db_password,
218
		$db_prefix,
219
		$language,
220
		$public_key
221
	) {
222 5
		$db_password = str_replace('"', '\\"', $db_password);
223 5
		$config      = str_replace(
224 5
			['@domain', '@timezone', '@db_host', '@db_driver', '@db_name', '@db_user', '@db_password', '@db_prefix', '@language', '@public_key'],
225 5
			[$domain, $timezone, $db_host, $db_driver, $db_name, $db_user, $db_password, $db_prefix, $language, $public_key],
226 5
			self::MAIN_CONFIG_STUB
227
		);
228 5
		if (!file_put_contents("$target/config/main.json", $config)) {
229
			throw new RuntimeException("Can't write core system configuration! Installation aborted.");
230
		}
231 5
		chmod("$target/config/main.json", 0600);
232 5
	}
233
	/**
234
	 * @param DB\_Abstract $cdb
235
	 * @param string       $source
236
	 * @param string       $db_driver
237
	 *
238
	 * @throws RuntimeException
239
	 */
240 5
	protected static function initialize_db_structure ($cdb, $source, $db_driver) {
241 5
		$query = array_filter(
242 5
			explode(';', file_get_contents("$source/DB/$db_driver.sql")),
243 5
			'trim'
244
		);
245 5
		if (!$cdb->q($query)) {
246
			throw new RuntimeException("Can't import system tables structure for selected database driver! Installation aborted.");
247
		}
248 5
	}
249
	/**
250
	 * @param DB\_Abstract $cdb
251
	 * @param string       $source
252
	 * @param string       $site_name
253
	 * @param string       $url
254
	 * @param string       $admin_email
255
	 * @param string       $language
256
	 * @param string       $domain
257
	 * @param string       $timezone
258
	 * @param int          $mode
259
	 *
260
	 * @throws RuntimeException
261
	 */
262 5
	protected static function initialize_system_config ($cdb, $source, $site_name, $url, $admin_email, $language, $domain, $timezone, $mode) {
263
		$config     = [
264 5
			'site_name'         => $site_name,
265 5
			'url'               => [$url],
266 5
			'admin_email'       => $admin_email,
267 5
			'language'          => $language,
268 5
			'active_languages'  => [$language],
269 5
			'cookie_domain'     => [$domain],
270 5
			'timezone'          => $timezone,
271 5
			'mail_from'         => $admin_email,
272 5
			'mail_from_name'    => "Administrator of $site_name",
273 5
			'simple_admin_mode' => $mode
274
		];
275
		$components = [
276 5
			'modules' => [
277
				'System' => [
278 5
					'active' => Config\Module_Properties::ENABLED,
279
					'db'     => [
280
						'keys'  => 0,
281
						'users' => 0,
282
						'texts' => 0
283
					]
284
				]
285
			],
286
			'blocks'  => []
287
		];
288 5
		foreach (file_get_json("$source/modules.json") as $module) {
289
			$components['modules'][$module] = [
290
				'active'  => Config\Module_Properties::UNINSTALLED,
291
				'db'      => [],
292
				'storage' => []
293
			];
294
		}
295 5
		$result = $cdb->q(
296 5
			"INSERT INTO `[prefix]config` (
297
				`domain`, `core`, `db`, `storage`, `components`
298
			) VALUES (
299
				'%s', '%s', '[]', '[]', '%s'
300
			)",
301 5
			$domain,
0 ignored issues
show
Bug introduced by
$domain of type string is incompatible with the type array expected by parameter $parameters of cs\DB\_Abstract::q(). ( Ignorable by Annotation )

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

301
			/** @scrutinizer ignore-type */ $domain,
Loading history...
302 5
			_json_encode($config),
303 5
			_json_encode($components)
304
		);
305 5
		if (!$result) {
0 ignored issues
show
introduced by
The condition $result is always false.
Loading history...
306
			throw new RuntimeException("Can't import system configuration into database! Installation aborted.");
307
		}
308 5
	}
309
	/**
310
	 * @param DB\_Abstract $cdb
311
	 * @param string       $admin_email
312
	 * @param string       $admin_password
313
	 * @param string       $public_key
314
	 *
315
	 * @throws RuntimeException
316
	 */
317 5
	protected static function create_root_administrator ($cdb, $admin_email, $admin_password, $public_key) {
318 5
		$admin_email = strtolower($admin_email);
319 5
		$admin_login = strstr($admin_email, '@', true);
320 5
		$result      = $cdb->q(
321 5
			"INSERT INTO `[prefix]users` (
322
				`login`, `login_hash`, `password_hash`, `email`, `email_hash`, `reg_date`, `reg_ip`, `status`
323
			) VALUES (
324
				'%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s'
325
			)",
326 5
			$admin_login,
0 ignored issues
show
Bug introduced by
$admin_login of type string is incompatible with the type array expected by parameter $parameters of cs\DB\_Abstract::q(). ( Ignorable by Annotation )

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

326
			/** @scrutinizer ignore-type */ $admin_login,
Loading history...
327 5
			hash('sha224', $admin_login),
328 5
			password_hash(hash('sha512', hash('sha512', $admin_password).$public_key), PASSWORD_DEFAULT),
329 5
			$admin_email,
330 5
			hash('sha224', $admin_email),
331 5
			time(),
0 ignored issues
show
Bug introduced by
time() of type integer is incompatible with the type array expected by parameter $parameters of cs\DB\_Abstract::q(). ( Ignorable by Annotation )

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

331
			/** @scrutinizer ignore-type */ time(),
Loading history...
332 5
			'127.0.0.1',
333 5
			User::STATUS_ACTIVE
334
		);
335 5
		if (!$result) {
0 ignored issues
show
introduced by
The condition $result is always false.
Loading history...
336
			throw new RuntimeException("Can't register root administrator user! Installation aborted.");
337
		}
338 5
	}
339
}
340