Completed
Push — master ( 59445a...e38094 )
by Nazar
11:05
created

Builder::get_component_files()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 28
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3.0327

Importance

Changes 0
Metric Value
cc 3
eloc 16
nc 3
nop 2
dl 0
loc 28
ccs 11
cts 13
cp 0.8462
crap 3.0327
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package    CleverStyle Framework
4
 * @subpackage Builder
5
 * @author     Nazar Mokrynskyi <[email protected]>
6
 * @copyright  Copyright (c) 2011-2016, 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 11
	function __construct ($root, $target) {
27 11
		$this->root   = $root;
28 11
		$this->target = $target;
29 11
		@mkdir($target);
30 11
	}
31
	/**
32
	 * @param string[]    $modules
33
	 * @param string[]    $themes
34
	 * @param null|string $suffix
35
	 *
36
	 * @return string
37
	 */
38 7
	function core ($modules = [], $themes = [], $suffix = null) {
39 7
		$suffix      = $suffix ? "_$suffix" : '';
40 7
		$version     = file_get_json("$this->root/modules/System/meta.json")['version'];
41 7
		$target_file = "$this->target/CleverStyle_Framework_$version$suffix.phar.php";
42 7
		if (file_exists($target_file)) {
43
			unlink($target_file);
44
		}
45 7
		$phar = new Phar($target_file);
46 7
		unset($target_file);
47 7
		$phar->startBuffering();
48 7
		$length = strlen("$this->root/");
49 7
		foreach (get_files_list("$this->root/install", false, 'f', '', true) as $file) {
50 7
			$phar->addFile("$this->root/install/$file", $file);
51
		}
52 7
		unset($file);
53 7
		$phar->addFile("$this->root/includes/img/logo.svg", 'logo.svg');
54
		/**
55
		 * Core files to be included into installation package
56
		 */
57 7
		$core_files = $this->get_core_files();
58
		/**
59
		 * Add modules that should be built-in into package
60
		 */
61 7
		$components_files = [];
62 7
		$modules          = $this->filter_and_add_components("$this->root/modules", $modules, $components_files);
63 7
		$phar->addFromString('modules.json', _json_encode($modules));
64
		/**
65
		 * Add themes that should be built-in into package
66
		 */
67 7
		$themes = $this->filter_and_add_components("$this->root/themes", $themes, $components_files);
68 7
		$phar->addFromString('themes.json', _json_encode($themes));
69
		/**
70
		 * Joining system and components files
71
		 */
72 7
		$core_files = array_merge($core_files, $components_files);
73
		/**
74
		 * Addition of files into package
75
		 */
76 7
		foreach ($core_files as $index => &$file) {
77 7
			$phar->addFile($file, "fs/$index");
78 7
			$file = substr($file, $length);
79
		}
80 7
		unset($index, $file);
81
		/**
82
		 * Addition of separate files into package
83
		 */
84 7
		$phar->addFromString(
85 7
			'languages.json',
86
			_json_encode(
87
				array_merge(
88 7
					_substr(get_files_list("$this->root/core/languages", '/^.*?\.php$/i', 'f'), 0, -4) ?: [],
89 7
					_substr(get_files_list("$this->root/core/languages", '/^.*?\.json$/i', 'f'), 0, -5) ?: []
90
				)
91
			)
92
		);
93 7
		$phar->addFromString(
94 7
			'db_engines.json',
95
			_json_encode(
96 7
				_substr(get_files_list("$this->root/core/engines/DB", '/^[^_].*?\.php$/i', 'f'), 0, -4)
97
			)
98
		);
99
		/**
100
		 * Fixation of system files list (without components files), it is needed for future system updating
101
		 */
102 7
		$phar->addFromString(
103 7
			'fs.json',
104
			_json_encode(
105
				array_flip(
106
					array_diff(
107
						$core_files,
108
						_substr($components_files, $length)
109
					)
110
				)
111
			)
112
		);
113 7
		unset($components_files, $length);
114
		/**
115
		 * Addition of files, that are needed only for installation
116
		 */
117 7
		$phar->addFromString('fs/'.count($core_files), $this->get_htaccess());
118 7
		$core_files[] = '.htaccess';
119 7
		$phar->addFile("$this->root/config/main.php", 'fs/'.count($core_files));
120 7
		$core_files[] = 'config/main.php';
121 7
		$phar->addFile("$this->root/favicon.ico", 'fs/'.count($core_files));
122 7
		$core_files[] = 'favicon.ico';
123 7
		$phar->addFile("$this->root/.gitignore", 'fs/'.count($core_files));
124 7
		$core_files[] = '.gitignore';
125
		/**
126
		 * Flip array to have direct access to files by name during extracting and installation, and fixing of files list for installation
127
		 */
128 7
		$phar->addFromString(
129 7
			'fs_installer.json',
130
			_json_encode(
131
				array_flip($core_files)
132
			)
133
		);
134 7
		unset($core_files);
135
		/**
136
		 * Addition of supplementary files, that are needed directly for installation process: installer with GUI interface, readme, license, some additional
137
		 * information about available languages, themes, current version of system
138
		 */
139 7
		$phar->addFile("$this->root/license.txt", 'license.txt');
140 7
		$phar->addFile("$this->root/modules/System/meta.json", 'meta.json');
141 7
		$phar->setStub(
142
		/** @lang PHP */
143
			<<<STUB
144
<?php
145
if (version_compare(PHP_VERSION, '5.6', '<')) {
146
	echo 'CleverStyle Framework require PHP 5.6 or higher';
147
	return;
148
}
149
150
if (PHP_SAPI == 'cli') {
151
	Phar::mapPhar('cleverstyle_framework.phar');
152
	include 'phar://cleverstyle_framework.phar/cli.php';
153
} else {
154
	Phar::webPhar(null, 'web.php');
155
}
156 7
__HALT_COMPILER();
157
STUB
158
		);
159 7
		$phar->stopBuffering();
160 7
		return "Done! CleverStyle Framework $version";
161
	}
162
	/**
163
	 * Get array of files
164
	 *
165
	 * @return string[]
166
	 */
167 7
	protected function get_core_files () {
168
		$files_to_include = [
169 7
			"$this->root/modules/System",
170 7
			"$this->root/blocks/.gitkept",
171 7
			"$this->root/core",
172 7
			"$this->root/custom",
173 7
			"$this->root/includes",
174 7
			"$this->root/storage/.htaccess",
175 7
			"$this->root/storage/pcache/.htaccess",
176 7
			"$this->root/storage/public/.htaccess",
177 7
			"$this->root/storage/temp/.htaccess",
178 7
			"$this->root/themes/CleverStyle",
179 7
			"$this->root/bower.json",
180 7
			"$this->root/cli",
181 7
			"$this->root/composer.json",
182 7
			"$this->root/composer.lock",
183 7
			"$this->root/index.php",
184 7
			"$this->root/license.txt",
185 7
			"$this->root/package.json"
186
		];
187 7
		$files            = [];
188 7
		foreach ($files_to_include as $s) {
189 7
			if (is_file($s)) {
190 7
				$files[] = $s;
191 7
			} elseif (is_dir($s)) {
192
				/** @noinspection SlowArrayOperationsInLoopInspection */
193 7
				$files = array_merge(
194
					$files,
195 7
					get_files_list($s, false, 'f', true, true, false, false, true)
196
				);
197
			}
198
		}
199 7
		return $files;
200
	}
201
	/**
202
	 * @param string   $dir
203
	 * @param string[] $components
204
	 * @param string[] $components_files
205
	 *
206
	 * @return string[]
207
	 */
208 7
	protected function filter_and_add_components ($dir, $components, &$components_files) {
209 7
		$components = array_filter(
210
			$components,
211 7
			function ($component) use ($dir, &$components_files) {
212 1
				return $this->get_component_files("$dir/$component", $components_files);
213 7
			}
214
		);
215 7
		sort($components);
216 7
		return $components;
217
	}
218
	/**
219
	 * @param string   $component_root
220
	 * @param string[] $files Array, where new files will be appended
221
	 *
222
	 * @return bool
223
	 */
224 1
	protected function get_component_files ($component_root, &$files) {
225
		/**
226
		 * Do not allow building System module and CleverStyle theme
227
		 */
228 1
		if (in_array(basename($component_root), ['System', 'CleverStyle'])) {
229
			return false;
230
		}
231
		/**
232
		 * Components without meta.json also not allowed
233
		 */
234 1
		if (!file_exists("$component_root/meta.json")) {
235
			return false;
236
		}
237 1
		@unlink("$component_root/fs.json");
238 1
		$local_files = get_files_list($component_root, false, 'f', true, true, false, false, true);
239 1
		$files       = array_merge($files, $local_files);
240 1
		file_put_json(
241 1
			"$component_root/fs.json",
242
			array_values(
243
				_substr(
244
					$local_files,
245 1
					strlen("$component_root/")
246
				)
247
			)
248
		);
249 1
		$files[] = "$component_root/fs.json";
250 1
		return true;
251
	}
252
	/**
253
	 * @return string
254
	 */
255 7
	protected function get_htaccess () {
256
		/** @lang ApacheConfig */
257
		return <<<HTACCESS
258
AddDefaultCharset utf-8
259
Options -Indexes -Multiviews +FollowSymLinks
260
IndexIgnore *.php *.pl *.cgi *.htaccess *.htpasswd
261
FileETag None
262
263
RewriteEngine On
264
RewriteBase /
265
266
<FilesMatch ".*/.*">
267
	Options -FollowSymLinks
268
</FilesMatch>
269
<FilesMatch "\.(css|js|gif|jpg|jpeg|png|ico|svg|svgz|ttc|ttf|otf|woff|woff2|eot)$">
270
	RewriteEngine Off
271
</FilesMatch>
272
<FilesMatch "\.(css|js|gif|jpg|jpeg|png|ico|svg|svgz|ttc|ttf|otf|woff|woff2|eot|html)$">
273
	<ifModule mod_expires.c>
274
		ExpiresActive On
275
		ExpiresDefault "access plus 1 month"
276
	</ifModule>
277
	<ifModule mod_headers.c>
278
		Header set Cache-Control "max-age=2592000, public"
279
	</ifModule>
280
</FilesMatch>
281
<Files license.txt>
282
	RewriteEngine Off
283
</Files>
284
285 7
RewriteRule .* index.php
286
HTACCESS;
287
	}
288
	/**
289
	 * @param string      $module
290
	 * @param null|string $suffix
291
	 *
292
	 * @return string
293
	 */
294 2
	function module ($module, $suffix = null) {
295 2
		if ($module == 'System') {
296
			return "Can't build module, System module is a part of core, it is not necessary to build it as separate module";
297
		}
298 2
		return $this->generic_package_creation("$this->root/modules/$module", $suffix);
299
	}
300
	/**
301
	 * @param string      $theme
302
	 * @param null|string $suffix
303
	 *
304
	 * @return string
305
	 */
306 2
	function theme ($theme, $suffix = null) {
307 2
		if ($theme == 'CleverStyle') {
308
			return "Can't build theme, CleverStyle theme is a part of core, it is not necessary to build it as separate theme";
309
		}
310 2
		return $this->generic_package_creation("$this->root/themes/$theme", $suffix);
311
	}
312 4
	protected function generic_package_creation ($source_dir, $suffix = null) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
313 4
		if (!file_exists("$source_dir/meta.json")) {
314
			$component = basename($source_dir);
315
			return "Can't build $component, meta information (meta.json) not found";
316
		}
317 4
		$meta = file_get_json("$source_dir/meta.json");
318 4
		$type = '';
319 4
		$Type = '';
320 4
		switch ($meta['category']) {
321 4
			case 'modules':
322 2
				$type = 'module_';
323 2
				$Type = 'Module';
324 2
				break;
325 2
			case 'themes':
326 2
				$type = 'theme_';
327 2
				$Type = 'Theme';
328 2
				break;
329
		}
330 4
		$suffix      = $suffix ? "_$suffix" : '';
331 4
		$target_file = "$this->target/$type$meta[package]_$meta[version]$suffix.phar.php";
332 4
		if (file_exists($target_file)) {
333
			unlink($target_file);
334
		}
335 4
		$phar = new Phar($target_file);
336 4
		unset($target_file);
337 4
		$phar->startBuffering();
338 4
		@unlink("$source_dir/fs.json");
339 4
		$files  = get_files_list($source_dir, false, 'f', true, true, false, false, true);
340 4
		$length = strlen("$source_dir/");
341 4
		foreach ($files as $index => &$file) {
342 4
			$phar->addFile($file, "fs/$index");
343 4
			$file = substr($file, $length);
344
		}
345 4
		unset($index, $file, $length);
346
		/**
347
		 * Flip array to have direct access to files by name during extraction
348
		 */
349 4
		$phar->addFromString(
350 4
			'fs.json',
351
			_json_encode(
352
				array_flip($files)
353
			)
354
		);
355 4
		unset($files);
356 4
		$phar->addFile("$source_dir/meta.json", 'meta.json');
357 4
		$readme = false;
358 4
		if (file_exists("$source_dir/readme.html")) {
359
			$phar->addFile("$source_dir/readme.html", 'readme.html');
360
			$readme = 'readme.html';
361 4
		} elseif (file_exists("$source_dir/readme.txt")) {
362
			$phar->addFile("$source_dir/readme.txt", 'readme.txt');
363
			$readme = 'readme.txt';
364
		}
365 4
		if ($readme) {
366
			$phar->setStub("<?php Phar::webPhar(null, '$readme'); __HALT_COMPILER();");
367
		} else {
368 4
			$phar->addFromString('index.html', isset($meta['description']) ? $meta['description'] : $meta['package']);
369 4
			$phar->setStub("<?php Phar::webPhar(null, 'index.html'); __HALT_COMPILER();");
370
		}
371 4
		$phar->stopBuffering();
372 4
		return "Done! $Type $meta[package] $meta[version]";
373
	}
374
}
375