Completed
Push — master ( bf102e...fafcea )
by Nazar
06:46
created

Installer::install()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 48
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 3.0004

Importance

Changes 0
Metric Value
cc 3
eloc 41
nc 2
nop 15
dl 0
loc 48
ccs 26
cts 27
cp 0.963
crap 3.0004
rs 9.125
c 0
b 0
f 0

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