Completed
Push — master ( a88bf0...125b25 )
by Nazar
04:02
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 13
CRAP Score 3

Importance

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