Completed
Push — master ( fab357...0ba320 )
by Nazar
07:50
created

Builder::generic_package_creation()   C

Complexity

Conditions 11
Paths 145

Size

Total Lines 63
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 132

Importance

Changes 0
Metric Value
cc 11
eloc 50
nc 145
nop 2
dl 0
loc 63
ccs 0
cts 49
cp 0
crap 132
rs 5.6779
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @package    CleverStyle Framework
4
 * @subpackage Builder
5
 * @author     Nazar Mokrynskyi <[email protected]>
6
 * @copyright  Copyright (c) 2011-2017, Nazar Mokrynskyi
7
 * @license    MIT License, see license.txt
8
 */
9
namespace cs;
10
use
11
	Phar;
12
13
class Builder {
14
	/**
15
	 * @var string
16
	 */
17
	protected $root;
18
	/**
19
	 * @var string
20
	 */
21
	protected $target;
22
	/**
23
	 * @param string $root
24
	 * @param string $target
25
	 */
26 2
	public function __construct ($root, $target) {
27 2
		$this->root   = $root;
28 2
		$this->target = $target;
29
		/** @noinspection MkdirRaceConditionInspection */
30 2
		@mkdir($target);
31 2
	}
32
	/**
33
	 * @param string[]    $modules
34
	 * @param string[]    $themes
35
	 * @param null|string $suffix
36
	 *
37
	 * @return string
38
	 *
39
	 * @throws \UnexpectedValueException
40
	 * @throws \BadMethodCallException
41
	 */
42 2
	public function core ($modules = [], $themes = [], $suffix = null) {
43 2
		$suffix      = $suffix ? "_$suffix" : '';
44 2
		$version     = file_get_json("$this->root/modules/System/meta.json")['version'];
45 2
		$target_file = "$this->target/CleverStyle_Framework_$version$suffix.phar.php";
46 2
		if (file_exists($target_file)) {
47
			unlink($target_file);
48
		}
49 2
		$phar = new Phar($target_file);
50 2
		unset($target_file);
51 2
		$phar->startBuffering();
52 2
		$length = strlen("$this->root/");
53
		/** @noinspection ForeachSourceInspection */
54 2
		foreach (get_files_list("$this->root/install", false, 'f', '', true) as $file) {
55 2
			$phar->addFile("$this->root/install/$file", $file);
56
		}
57 2
		unset($file);
58 2
		$phar->addFile("$this->root/assets/img/logo.svg", 'logo.svg');
59
		/**
60
		 * Core files to be included into installation package
61
		 */
62 2
		$core_files = $this->get_core_files();
63
		/**
64
		 * Add modules that should be built-in into package
65
		 */
66 2
		$components_files = [];
67 2
		$modules          = $this->filter_and_add_components("$this->root/modules", $modules, $components_files);
68 2
		$phar->addFromString('modules.json', _json_encode($modules));
69
		/**
70
		 * Add themes that should be built-in into package
71
		 */
72 2
		$themes = $this->filter_and_add_components("$this->root/themes", $themes, $components_files);
73 2
		$phar->addFromString('themes.json', _json_encode($themes));
74
		/**
75
		 * Joining system and components files
76
		 */
77 2
		$core_files = array_merge($core_files, $components_files);
78
		/**
79
		 * Addition of files into package
80
		 */
81 2
		foreach ($core_files as $index => &$file) {
82 2
			$phar->addFile($file, "fs/$index");
83 2
			$file = substr($file, $length);
84
		}
85 2
		unset($index, $file);
86
		/**
87
		 * Add license under the file `license-cleverstyle-framework.txt` rather than `license.txt`, so that license is not enforced on projects using it and is
88
		 * not overridden on framework update
89
		 */
90 2
		$phar->addFile("$this->root/license.txt", 'fs/'.count($core_files));
91 2
		$core_files[] = 'license-cleverstyle-framework.txt';
92
		/**
93
		 * Addition of separate files into package
94
		 */
95 2
		$phar->addFromString(
96 2
			'languages.json',
97 2
			_json_encode(
98 2
				array_merge(
99 2
					_substr(get_files_list("$this->root/core/languages", '/^.*?\.php$/i', 'f'), 0, -4) ?: [],
100 2
					_substr(get_files_list("$this->root/core/languages", '/^.*?\.json$/i', 'f'), 0, -5) ?: []
101
				)
102
			)
103
		);
104 2
		$phar->addFromString(
105 2
			'db_drivers.json',
106 2
			_json_encode(
107 2
				_substr(get_files_list("$this->root/core/drivers/DB", '/^[^_].*?\.php$/i', 'f'), 0, -4)
108
			)
109
		);
110
		/**
111
		 * Fixation of system files list (without components files), it is needed for future system updating
112
		 */
113 2
		$phar->addFromString(
114 2
			'fs.json',
115 2
			_json_encode(
116 2
				array_flip(
117 2
					array_diff(
118 2
						$core_files,
119 2
						_substr($components_files, $length)
120
					)
121
				)
122
			)
123
		);
124 2
		unset($components_files, $length);
125
		/**
126
		 * Addition of files, that are needed only for installation
127
		 */
128 2
		$phar->addFromString('fs/'.count($core_files), $this->get_htaccess());
129 2
		$core_files[] = '.htaccess';
130 2
		$phar->addFile("$this->root/config/main.php", 'fs/'.count($core_files));
131 2
		$core_files[] = 'config/main.php';
132 2
		$phar->addFile("$this->root/favicon.ico", 'fs/'.count($core_files));
133 2
		$core_files[] = 'favicon.ico';
134 2
		$phar->addFile("$this->root/.gitignore", 'fs/'.count($core_files));
135 2
		$core_files[] = '.gitignore';
136
		/**
137
		 * Flip array to have direct access to files by name during extracting and installation, and fixing of files list for installation
138
		 */
139 2
		$phar->addFromString(
140 2
			'fs_installer.json',
141 2
			_json_encode(
142 2
				array_flip($core_files)
143
			)
144
		);
145 2
		unset($core_files);
146
		/**
147
		 * Addition of supplementary files, that are needed directly for installation process: installer with GUI interface, readme, license, some additional
148
		 * information about available languages, themes, current version of system
149
		 */
150 2
		$phar->addFile("$this->root/license.txt", 'license.txt');
151 2
		$phar->addFile("$this->root/modules/System/meta.json", 'meta.json');
152 2
		$phar->setStub(
153
		/** @lang PHP */
154
			<<<STUB
155 2
<?php
156
if (version_compare(PHP_VERSION, '7.0', '<')) {
157
	echo 'CleverStyle Framework requires PHP 7.0 or higher';
158
	return;
159
}
160
161
if (php_sapi_name() == 'cli') {
162
	Phar::mapPhar('cleverstyle_framework.phar');
163
	include 'phar://cleverstyle_framework.phar/cli.php';
164
} else {
165
	Phar::webPhar(null, 'web.php');
166
}
167
__HALT_COMPILER();
168
STUB
169
		);
170 2
		$phar->stopBuffering();
171 2
		return "Done! CleverStyle Framework $version";
172
	}
173
	/**
174
	 * Get array of files
175
	 *
176
	 * @return string[]
177
	 */
178 2
	protected function get_core_files () {
179
		$files_to_include = [
180 2
			"$this->root/assets",
181 2
			"$this->root/blocks/.gitkept",
182 2
			"$this->root/core",
183 2
			"$this->root/custom",
184 2
			"$this->root/modules/System",
185 2
			"$this->root/storage/.htaccess",
186 2
			"$this->root/storage/public_cache/.htaccess",
187 2
			"$this->root/storage/public/.htaccess",
188 2
			"$this->root/storage/temp/.htaccess",
189 2
			"$this->root/themes/CleverStyle",
190 2
			"$this->root/bower.json",
191 2
			"$this->root/cli",
192 2
			"$this->root/composer.json",
193 2
			"$this->root/composer.lock",
194 2
			"$this->root/index.php",
195 2
			"$this->root/package.json"
196
		];
197 2
		$files            = [];
198 2
		foreach ($files_to_include as $s) {
199 2
			if (is_file($s)) {
200 2
				$files[] = $s;
201 2
			} elseif (is_dir($s)) {
202
				/** @noinspection SlowArrayOperationsInLoopInspection */
203 2
				$files = array_merge(
204 2
					$files,
205 2
					get_files_list($s, false, 'f', true, true, false, false, true)
206
				);
207
			}
208
		}
209 2
		return $files;
210
	}
211
	/**
212
	 * @param string   $dir
213
	 * @param string[] $components
214
	 * @param string[] $components_files
215
	 *
216
	 * @return string[]
217
	 */
218 2
	protected function filter_and_add_components ($dir, $components, &$components_files) {
219 2
		$components = array_filter(
220 2
			$components,
221 2
			function ($component) use ($dir, &$components_files) {
222
				return $this->get_component_files("$dir/$component", $components_files);
223 2
			}
224
		);
225 2
		sort($components);
226 2
		return $components;
227
	}
228
	/**
229
	 * @param string   $component_root
230
	 * @param string[] $files Array, where new files will be appended
231
	 *
232
	 * @return bool
233
	 */
234
	protected function get_component_files ($component_root, &$files) {
235
		/**
236
		 * Do not allow building System module and CleverStyle theme
237
		 */
238
		if (in_array(basename($component_root), ['System', 'CleverStyle'])) {
239
			return false;
240
		}
241
		/**
242
		 * Components without meta.json also not allowed
243
		 */
244
		if (!file_exists("$component_root/meta.json")) {
245
			return false;
246
		}
247
		@unlink("$component_root/fs.json");
248
		$local_files = get_files_list($component_root, false, 'f', true, true, false, false, true);
249
		$files       = array_merge($files, $local_files);
250
		file_put_json(
251
			"$component_root/fs.json",
252
			array_values(
253
				_substr(
254
					$local_files,
255
					strlen("$component_root/")
256
				)
257
			)
258
		);
259
		$files[] = "$component_root/fs.json";
260
		return true;
261
	}
262
	/**
263
	 * @return string
264
	 */
265 2
	protected function get_htaccess () {
266
		/** @lang ApacheConfig */
267
		return <<<HTACCESS
268 2
AddDefaultCharset utf-8
269
Options -Indexes -Multiviews +FollowSymLinks
270
IndexIgnore *.php *.pl *.cgi *.htaccess *.htpasswd
271
FileETag None
272
273
RewriteEngine On
274
RewriteBase /
275
276
<FilesMatch ".*/.*">
277
	Options -FollowSymLinks
278
</FilesMatch>
279
<FilesMatch "\.(css|js|gif|jpg|jpeg|png|ico|svg|svgz|ttc|ttf|otf|woff|woff2|eot)$">
280
	RewriteEngine Off
281
</FilesMatch>
282
<FilesMatch "\.(css|js|gif|jpg|jpeg|png|ico|svg|svgz|ttc|ttf|otf|woff|woff2|eot|html)$">
283
	<ifModule mod_expires.c>
284
		ExpiresActive On
285
		ExpiresDefault "access plus 1 month"
286
	</ifModule>
287
	<ifModule mod_headers.c>
288
		Header set Cache-Control "max-age=2592000, immutable"
289
	</ifModule>
290
</FilesMatch>
291
<Files license.txt>
292
	RewriteEngine Off
293
</Files>
294
295
RewriteRule .* index.php
296
HTACCESS;
297
	}
298
	/**
299
	 * @param string      $module
300
	 * @param null|string $suffix
301
	 *
302
	 * @return string
303
	 */
304
	public function module ($module, $suffix = null) {
305
		if ($module == 'System') {
306
			return "Can't build module, System module is a part of core, it is not necessary to build it as separate module";
307
		}
308
		return $this->generic_package_creation("$this->root/modules/$module", $suffix);
309
	}
310
	/**
311
	 * @param string      $theme
312
	 * @param null|string $suffix
313
	 *
314
	 * @return string
315
	 */
316
	public function theme ($theme, $suffix = null) {
317
		if ($theme == 'CleverStyle') {
318
			return "Can't build theme, CleverStyle theme is a part of core, it is not necessary to build it as separate theme";
319
		}
320
		return $this->generic_package_creation("$this->root/themes/$theme", $suffix);
321
	}
322
	/**
323
	 * @param string      $source_dir
324
	 * @param null|string $suffix
325
	 *
326
	 * @return string
327
	 */
328
	protected function generic_package_creation ($source_dir, $suffix = null) {
329
		if (!file_exists("$source_dir/meta.json")) {
330
			$component = basename($source_dir);
331
			return "Can't build $component, meta information (meta.json) not found";
332
		}
333
		$meta = file_get_json("$source_dir/meta.json");
334
		$type = '';
335
		$Type = '';
336
		switch ($meta['category']) {
337
			case 'modules':
338
				$type = 'module_';
339
				$Type = 'Module';
340
				break;
341
			case 'themes':
342
				$type = 'theme_';
343
				$Type = 'Theme';
344
				break;
345
		}
346
		$suffix      = $suffix ? "_$suffix" : '';
347
		$target_file = "$this->target/$type$meta[package]_$meta[version]$suffix.phar.php";
348
		if (file_exists($target_file)) {
349
			unlink($target_file);
350
		}
351
		$phar = new Phar($target_file);
352
		unset($target_file);
353
		$phar->startBuffering();
354
		@unlink("$source_dir/fs.json");
355
		$files  = get_files_list($source_dir, false, 'f', true, true, false, false, true);
356
		$length = strlen("$source_dir/");
357
		/** @noinspection ForeachSourceInspection */
358
		foreach ($files as $index => &$file) {
359
			$phar->addFile($file, "fs/$index");
360
			$file = substr($file, $length);
361
		}
362
		unset($index, $file, $length);
363
		/**
364
		 * Flip array to have direct access to files by name during extraction
365
		 */
366
		$phar->addFromString(
367
			'fs.json',
368
			_json_encode(
369
				array_flip($files)
370
			)
371
		);
372
		unset($files);
373
		$phar->addFile("$source_dir/meta.json", 'meta.json');
374
		$readme = false;
375
		if (file_exists("$source_dir/readme.html")) {
376
			$phar->addFile("$source_dir/readme.html", 'readme.html');
377
			$readme = 'readme.html';
378
		} elseif (file_exists("$source_dir/readme.txt")) {
379
			$phar->addFile("$source_dir/readme.txt", 'readme.txt');
380
			$readme = 'readme.txt';
381
		}
382
		if ($readme) {
383
			$phar->setStub("<?php Phar::webPhar(null, '$readme'); __HALT_COMPILER();");
384
		} else {
385
			$phar->addFromString('index.html', isset($meta['description']) ? $meta['description'] : $meta['package']);
386
			$phar->setStub("<?php Phar::webPhar(null, 'index.html'); __HALT_COMPILER();");
387
		}
388
		$phar->stopBuffering();
389
		return "Done! $Type $meta[package] $meta[version]";
390
	}
391
}
392