Completed
Push — master ( 215c97...c1aac3 )
by Nazar
04:30
created

Includes   C

Complexity

Total Complexity 66

Size/Duplication

Total Lines 510
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 90.73%

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 510
rs 5.7474
ccs 186
cts 205
cp 0.9073
wmc 66
lcom 1
cbo 8

25 Methods

Rating   Name   Duplication   Size   Complexity  
A init_includes() 0 11 1
A html() 0 3 1
A html_internal() 0 3 1
A js() 0 3 1
A js_internal() 0 3 1
A css() 0 3 1
A css_internal() 0 3 1
B include_common() 0 21 7
A config() 0 3 1
A page_compression_usage() 0 3 3
A ie_edge() 0 10 2
A get_includes_and_preload_resource_for_page_with_compression() 0 12 3
C get_normalized_includes() 0 40 7
B get_dependency_component() 0 12 7
A absolute_path_to_relative() 0 3 1
A config_internal() 0 16 2
B add_includes_on_page() 0 38 3
A webcomponents_polyfill() 0 11 3
A add_script_imports_to_document() 0 7 2
A get_includes_for_page_without_compression() 0 6 1
A add_includes_on_page_manually_added() 0 16 4
A add_includes_on_page_manually_added_normal() 0 22 2
A add_preload() 0 9 2
B add_includes_on_page_manually_added_frontend_load_optimization() 0 35 6
A add_versions_hash() 0 16 3

How to fix   Complexity   

Complex Class

Complex classes like Includes often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Includes, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @package   CleverStyle Framework
4
 * @author    Nazar Mokrynskyi <[email protected]>
5
 * @copyright Copyright (c) 2014-2016, Nazar Mokrynskyi
6
 * @license   MIT License, see license.txt
7
 */
8
namespace cs\Page;
9
use
10
	cs\App,
11
	cs\Config,
12
	cs\Language,
13
	cs\Request,
14
	cs\Response,
15
	cs\User,
16
	h,
17
	cs\Page\Includes\Cache,
18
	cs\Page\Includes\Collecting,
19
	cs\Page\Includes\RequireJS;
20
21
/**
22
 * Includes management for `cs\Page` class
23
 *
24
 * @property string $Title
25
 * @property string $Description
26
 * @property string $canonical_url
27
 * @property string $Head
28
 * @property string $post_Body
29
 * @property string $theme
30
 */
31
trait Includes {
32
	use
33
		Cache,
34
		Collecting,
35
		RequireJS;
36
	protected $extension_to_as = [
37
		'jpeg' => 'image',
38
		'jpe'  => 'image',
39
		'jpg'  => 'image',
40
		'gif'  => 'image',
41
		'png'  => 'image',
42
		'svg'  => 'image',
43
		'svgz' => 'image',
44
		'woff' => 'font',
45
		//'woff2' => 'font',
46
		'css'  => 'style',
47
		'js'   => 'script',
48
		'html' => 'document'
49
	];
50
	/**
51
	 * @var array
52
	 */
53
	protected $core_html;
54
	/**
55
	 * @var array
56
	 */
57
	protected $core_js;
58
	/**
59
	 * @var array
60
	 */
61
	protected $core_css;
62
	/**
63
	 * @var string
64
	 */
65
	protected $core_config;
66
	/**
67
	 * @var array
68
	 */
69
	protected $html;
70
	/**
71
	 * @var array
72
	 */
73
	protected $js;
74
	/**
75
	 * @var array
76
	 */
77
	protected $css;
78
	/**
79
	 * @var string
80
	 */
81
	protected $config;
82
	/**
83
	 * Base name is used as prefix when creating CSS/JS/HTML cache files in order to avoid collisions when having several themes and languages
84
	 * @var string
85
	 */
86
	protected $pcache_basename_path;
87 36
	protected function init_includes () {
88 36
		$this->core_html            = ['path' => []]; // No plain HTML in core
89 36
		$this->core_js              = ['path' => []]; // No plain JS in core
90 36
		$this->core_css             = ['path' => []]; // No plain CSS in core
91 36
		$this->core_config          = '';
92 36
		$this->html                 = ['path' => [], 'plain' => ''];
93 36
		$this->js                   = ['path' => [], 'plain' => ''];
94 36
		$this->css                  = ['path' => [], 'plain' => ''];
95 36
		$this->config               = '';
96 36
		$this->pcache_basename_path = '';
97 36
	}
98
	/**
99
	 * Including of Web Components
100
	 *
101
	 * @param string|string[] $add  Path to including file, or code
102
	 * @param string          $mode Can be <b>file</b> or <b>code</b>
103
	 *
104
	 * @return \cs\Page
105
	 */
106
	function html ($add, $mode = 'file') {
107
		return $this->html_internal($add, $mode);
108
	}
109
	/**
110
	 * @param string|string[] $add
111
	 * @param string          $mode
112
	 * @param bool            $core
113
	 *
114
	 * @return \cs\Page
115
	 */
116 4
	protected function html_internal ($add, $mode = 'file', $core = false) {
117 4
		return $this->include_common('html', $add, $mode, $core);
118
	}
119
	/**
120
	 * Including of JavaScript
121
	 *
122
	 * @param string|string[] $add  Path to including file, or code
123
	 * @param string          $mode Can be <b>file</b> or <b>code</b>
124
	 *
125
	 * @return \cs\Page
126
	 */
127
	function js ($add, $mode = 'file') {
128
		return $this->js_internal($add, $mode);
129
	}
130
	/**
131
	 * @param string|string[] $add
132
	 * @param string          $mode
133
	 * @param bool            $core
134
	 *
135
	 * @return \cs\Page
136
	 */
137 4
	protected function js_internal ($add, $mode = 'file', $core = false) {
138 4
		return $this->include_common('js', $add, $mode, $core);
139
	}
140
	/**
141
	 * Including of CSS
142
	 *
143
	 * @param string|string[] $add  Path to including file, or code
144
	 * @param string          $mode Can be <b>file</b> or <b>code</b>
145
	 *
146
	 * @return \cs\Page
147
	 */
148
	function css ($add, $mode = 'file') {
149
		return $this->css_internal($add, $mode);
150
	}
151
	/**
152
	 * @param string|string[] $add
153
	 * @param string          $mode
154
	 * @param bool            $core
155
	 *
156
	 * @return \cs\Page
157
	 */
158 4
	protected function css_internal ($add, $mode = 'file', $core = false) {
159 4
		return $this->include_common('css', $add, $mode, $core);
160
	}
161
	/**
162
	 * @param string          $what
163
	 * @param string|string[] $add
164
	 * @param string          $mode
165
	 * @param bool            $core
166
	 *
167
	 * @return \cs\Page
168
	 */
169 4
	protected function include_common ($what, $add, $mode, $core) {
170 4
		if (!$add) {
171
			return $this;
172
		}
173 4
		if (is_array($add)) {
174 4
			foreach (array_filter($add) as $style) {
175 4
				$this->include_common($what, $style, $mode, $core);
176
			}
177
		} else {
178 4
			if ($core) {
179 4
				$what = "core_$what";
180
			}
181 4
			$target = &$this->$what;
182 4
			if ($mode == 'file') {
183 4
				$target['path'][] = $add;
184
			} elseif ($mode == 'code') {
185
				$target['plain'] .= "$add\n";
186
			}
187
		}
188 4
		return $this;
189
	}
190
	/**
191
	 * Add config on page to make it available on frontend
192
	 *
193
	 * @param mixed  $config_structure        Any scalar type or array
194
	 * @param string $target                  Target is property of `window` object where config will be inserted as value, nested properties like `cs.sub.prop`
195
	 *                                        are supported and all nested properties are created on demand. It is recommended to use sub-properties of `cs`
196
	 *
197
	 * @return \cs\Page
198
	 */
199 4
	function config ($config_structure, $target) {
200 4
		return $this->config_internal($config_structure, $target);
201
	}
202
	/**
203
	 * @param mixed  $config_structure
204
	 * @param string $target
205
	 * @param bool   $core
206
	 *
207
	 * @return \cs\Page
208
	 */
209 4
	protected function config_internal ($config_structure, $target, $core = false) {
210 4
		$config = h::script(
211 4
			json_encode($config_structure, JSON_UNESCAPED_UNICODE),
212
			[
213 4
				'target' => $target,
214 4
				'class'  => 'cs-config',
215 4
				'type'   => 'application/json'
216
			]
217
		);
218 4
		if ($core) {
219 2
			$this->core_config .= $config;
220
		} else {
221 4
			$this->config .= $config;
222
		}
223 4
		return $this;
224
	}
225
	/**
226
	 * Getting of HTML, JS and CSS includes
227
	 *
228
	 * @return \cs\Page
229
	 */
230 4
	protected function add_includes_on_page () {
231 4
		$Config = Config::instance(true);
232 4
		if (!$Config) {
233
			return $this;
234
		}
235
		/**
236
		 * Base name for cache files
237
		 */
238 4
		$this->pcache_basename_path = PUBLIC_CACHE.'/'.$this->theme.'_'.Language::instance()->clang;
239
		// TODO: I hope some day we'll get rid of this sh*t :(
240 4
		$this->ie_edge();
241 4
		$Request = Request::instance();
242
		/**
243
		 * If CSS and JavaScript compression enabled
244
		 */
245 4
		if ($this->page_compression_usage($Config, $Request)) {
246
			/**
247
			 * Rebuilding HTML, JS and CSS cache if necessary
248
			 */
249 4
			$this->rebuild_cache($Config);
250 4
			$this->webcomponents_polyfill($Request, $Config, true);
251 4
			list($includes, $preload) = $this->get_includes_and_preload_resource_for_page_with_compression($Request);
252
		} else {
253 2
			$this->webcomponents_polyfill($Request, $Config, false);
254
			/**
255
			 * Language translation is added explicitly only when compression is disabled, otherwise it will be in compressed JS file
256
			 */
257 2
			$this->config_internal(Language::instance(), 'cs.Language', true);
258 2
			$this->config_internal($this->get_requirejs_paths(), 'requirejs.paths', true);
259 2
			$includes = $this->get_includes_for_page_without_compression($Config, $Request);
260 2
			$preload  = [];
261
		}
262 4
		$this->css_internal($includes['css'], 'file', true);
263 4
		$this->js_internal($includes['js'], 'file', true);
264 4
		$this->html_internal($includes['html'], 'file', true);
265 4
		$this->add_includes_on_page_manually_added($Config, $Request, $preload);
266 4
		return $this;
267
	}
268
	/**
269
	 * @param Config  $Config
270
	 * @param Request $Request
271
	 *
272
	 * @return bool
273
	 */
274 4
	protected function page_compression_usage ($Config, $Request) {
275 4
		return $Config->core['cache_compress_js_css'] && !($Request->admin_path && isset($Request->query['debug']));
276
	}
277
	/**
278
	 * Add JS polyfills for IE/Edge
279
	 */
280 4
	protected function ie_edge () {
281 4
		if (!preg_match('/Trident|Edge/', Request::instance()->header('user-agent'))) {
282 4
			return;
283
		}
284
		$this->js_internal(
285
			get_files_list(DIR."/includes/js/microsoft_sh*t", "/.*\\.js$/i", 'f', "includes/js/microsoft_sh*t", true),
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal /includes/js/microsoft_sh*t does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
Coding Style Comprehensibility introduced by
The string literal /.*\\.js$/i does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
Coding Style Comprehensibility introduced by
The string literal includes/js/microsoft_sh*t does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
286
			'file',
287
			true
288
		);
289
	}
290
	/**
291
	 * Hack: Add WebComponents Polyfill for browsers without native Shadow DOM support
292
	 *
293
	 * @param Request $Request
294
	 * @param Config  $Config
295
	 * @param bool    $with_compression
296
	 */
297 4
	protected function webcomponents_polyfill ($Request, $Config, $with_compression) {
298 4
		if ($Request->cookie('shadow_dom') == 1) {
299
			return;
300
		}
301 4
		if ($with_compression) {
302 4
			$hash = file_get_contents(PUBLIC_CACHE.'/webcomponents.js.hash');
303 4
			$this->add_script_imports_to_document($Config, "<script src=\"/storage/pcache/webcomponents.js?$hash\"></script>\n");
304
		} else {
305 2
			$this->add_script_imports_to_document($Config, "<script src=\"/includes/js/WebComponents-polyfill/webcomponents-custom.min.js\"></script>\n");
306
		}
307 4
	}
308
	/**
309
	 * @param Config $Config
310
	 * @param string $content
311
	 */
312 4
	protected function add_script_imports_to_document ($Config, $content) {
313 4
		if ($Config->core['put_js_after_body']) {
314 4
			$this->post_Body .= $content;
315
		} else {
316 2
			$this->Head .= $content;
317
		}
318 4
	}
319
	/**
320
	 * @param Request $Request
321
	 *
322
	 * @return array[]
323
	 */
324 4
	protected function get_includes_and_preload_resource_for_page_with_compression ($Request) {
325 4
		list($dependencies, $compressed_includes_map, $not_embedded_resources_map) = file_get_json("$this->pcache_basename_path.json");
326 4
		$includes = $this->get_normalized_includes($dependencies, $compressed_includes_map, $Request);
327 4
		$preload  = [];
328 4
		foreach (array_merge(...array_values($includes)) as $path) {
329 4
			$preload[] = [$path];
330 4
			if (isset($not_embedded_resources_map[$path])) {
331 4
				$preload[] = $not_embedded_resources_map[$path];
332
			}
333
		}
334 4
		return [$includes, array_merge(...$preload)];
335
	}
336
	/**
337
	 * @param array      $dependencies
338
	 * @param string[][] $includes_map
339
	 * @param Request    $Request
340
	 *
341
	 * @return string[][]
342
	 */
343 4
	protected function get_normalized_includes ($dependencies, $includes_map, $Request) {
344 4
		$current_module = $Request->current_module;
345
		/**
346
		 * Current URL based on controller path (it better represents how page was rendered)
347
		 */
348 4
		$current_url = array_slice(App::instance()->controller_path, 1);
349 4
		$current_url = ($Request->admin_path ? "admin/" : '')."$current_module/".implode('/', $current_url);
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal admin/ does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
350
		/**
351
		 * Narrow the dependencies to current module only
352
		 */
353 4
		$dependencies    = array_unique(
354
			array_merge(
355 4
				['System'],
356 4
				$dependencies['System'],
357 4
				isset($dependencies[$current_module]) ? $dependencies[$current_module] : []
358
			)
359
		);
360 4
		$system_includes = [];
361
		// Array with empty array in order to avoid `array_merge()` failure later
362 4
		$dependencies_includes = array_fill_keys($dependencies, [[]]);
363 4
		$includes              = [];
364 4
		foreach ($includes_map as $path => $local_includes) {
365 4
			if ($path == 'System') {
366 4
				$system_includes = $local_includes;
367 4
			} elseif ($component = $this->get_dependency_component($dependencies, $path, $Request)) {
368
				/**
369
				 * @var string $component
370
				 */
371
				$dependencies_includes[$component][] = $local_includes;
372 4
			} elseif (mb_strpos($current_url, $path) === 0) {
373 4
				$includes[] = $local_includes;
374
			}
375
		}
376
		// Convert to indexed array first
377 4
		$dependencies_includes = array_values($dependencies_includes);
378
		// Flatten array on higher level
379 4
		$dependencies_includes = array_merge(...$dependencies_includes);
380
		// Hack: 2 array_merge_recursive() just to be compatible with HHVM, simplify when https://github.com/facebook/hhvm/issues/7087 is resolved
381 4
		return _array(array_merge_recursive(array_merge_recursive($system_includes, ...$dependencies_includes), ...$includes));
382
	}
383
	/**
384
	 * @param array   $dependencies
385
	 * @param string  $url
386
	 * @param Request $Request
387
	 *
388
	 * @return false|string
389
	 */
390 4
	protected function get_dependency_component ($dependencies, $url, $Request) {
391 4
		$url_exploded = explode('/', $url);
392
		/** @noinspection NestedTernaryOperatorInspection */
393 4
		$url_component = $url_exploded[0] != 'admin' ? $url_exploded[0] : (@$url_exploded[1] ?: '');
394
		$is_dependency =
395 4
			$url_component !== Config::SYSTEM_MODULE &&
396 4
			in_array($url_component, $dependencies) &&
397
			(
398 4
				$Request->admin_path || $Request->admin_path == ($url_exploded[0] == 'admin')
399
			);
400 4
		return $is_dependency ? $url_component : false;
401
	}
402
	/**
403
	 * @param Config  $Config
404
	 * @param Request $Request
405
	 *
406
	 * @return string[][]
407
	 */
408 2
	protected function get_includes_for_page_without_compression ($Config, $Request) {
409
		// To determine all dependencies and stuff we need `$Config` object to be already created
410 2
		list($dependencies, $includes_map) = $this->get_includes_dependencies_and_map($Config);
411 2
		$includes = $this->get_normalized_includes($dependencies, $includes_map, $Request);
412 2
		return $this->add_versions_hash($this->absolute_path_to_relative($includes));
413
	}
414
	/**
415
	 * @param string[]|string[][] $path
416
	 *
417
	 * @return string[]|string[][]
418
	 */
419 4
	protected function absolute_path_to_relative ($path) {
420 4
		return _substr($path, strlen(DIR));
421
	}
422
	/**
423
	 * @param string[][] $includes
424
	 *
425
	 * @return string[][]
426
	 */
427 2
	protected function add_versions_hash ($includes) {
428 2
		$content     = array_reduce(
429 2
			get_files_list(DIR.'/components', '/^meta\.json$/', 'f', true, true),
430
			function ($content, $file) {
431
				return $content.file_get_contents($file);
432 2
			}
433
		);
434 2
		$content_md5 = substr(md5($content), 0, 5);
435 2
		foreach ($includes as &$files) {
436 2
			foreach ($files as &$file) {
437 2
				$file .= "?$content_md5";
438
			}
439 2
			unset($file);
440
		}
441 2
		return $includes;
442
	}
443
	/**
444
	 * @param Config   $Config
445
	 * @param Request  $Request
446
	 * @param string[] $preload
447
	 */
448 4
	protected function add_includes_on_page_manually_added ($Config, $Request, $preload) {
449
		/** @noinspection NestedTernaryOperatorInspection */
450 4
		$this->Head .=
451 4
			array_reduce(
452 4
				array_merge($this->core_css['path'], $this->css['path']),
453
				function ($content, $href) {
454 4
					return "$content<link href=\"$href\" rel=\"stylesheet\">\n";
455 4
				}
456
			).
457 4
			h::style($this->css['plain'] ?: false);
458 4
		if ($this->page_compression_usage($Config, $Request) && $Config->core['frontend_load_optimization']) {
459 4
			$this->add_includes_on_page_manually_added_frontend_load_optimization($Config);
460
		} else {
461 2
			$this->add_includes_on_page_manually_added_normal($Config, $preload);
462
		}
463 4
	}
464
	/**
465
	 * @param Config   $Config
466
	 * @param string[] $preload
467
	 */
468 2
	protected function add_includes_on_page_manually_added_normal ($Config, $preload) {
469 2
		$this->add_preload($preload);
470 2
		$configs      = $this->core_config.$this->config;
471
		$scripts      =
472 2
			array_reduce(
473 2
				array_merge($this->core_js['path'], $this->js['path']),
474
				function ($content, $src) {
475 2
					return "$content<script src=\"$src\"></script>\n";
476 2
				}
477
			).
478 2
			h::script($this->js['plain'] ?: false);
479
		$html_imports =
480 2
			array_reduce(
481 2
				array_merge($this->core_html['path'], $this->html['path']),
482 2
				function ($content, $href) {
483 2
					return "$content<link href=\"$href\" rel=\"import\">\n";
484 2
				}
485
			).
486 2
			$this->html['plain'];
487 2
		$this->Head .= $configs;
488 2
		$this->add_script_imports_to_document($Config, $scripts.$html_imports);
489 2
	}
490
	/**
491
	 * @param string[] $preload
492
	 */
493 4
	protected function add_preload ($preload) {
494 4
		$Response = Response::instance();
495 4
		foreach ($preload as $resource) {
496 4
			$extension = explode('?', file_extension($resource))[0];
497 4
			$as        = $this->extension_to_as[$extension];
498 4
			$resource  = str_replace(' ', '%20', $resource);
499 4
			$Response->header('Link', "<$resource>; rel=preload; as=$as", false);
500
		}
501 4
	}
502
	/**
503
	 * @param Config $Config
504
	 */
505 4
	protected function add_includes_on_page_manually_added_frontend_load_optimization ($Config) {
506 4
		list($optimized_includes, $preload) = file_get_json("$this->pcache_basename_path.optimized.json");
507 4
		$this->add_preload(
508
			array_unique(
509
				array_merge(
510
					$preload,
511 4
					$this->core_css['path'],
512 4
					$this->css['path']
513
				)
514
			)
515
		);
516 4
		$system_scripts    = '';
517 4
		$optimized_scripts = [];
518 4
		$system_imports    = '';
519 4
		$optimized_imports = [];
520 4
		foreach (array_merge($this->core_js['path'], $this->js['path']) as $script) {
521 4
			if (isset($optimized_includes[$script])) {
522
				$optimized_scripts[] = $script;
523
			} else {
524 4
				$system_scripts .= "<script src=\"$script\"></script>\n";
525
			}
526
		}
527 4
		foreach (array_merge($this->core_html['path'], $this->html['path']) as $import) {
528 4
			if (isset($optimized_includes[$import])) {
529
				$optimized_imports[] = $import;
530
			} else {
531 4
				$system_imports .= "<link href=\"$import\" rel=\"import\">\n";
532
			}
533
		}
534 4
		$scripts      = h::script($this->js['plain'] ?: false);
535 4
		$html_imports = $this->html['plain'];
536 4
		$this->config([$optimized_scripts, $optimized_imports], 'cs.optimized_includes');
537 4
		$this->Head .= $this->core_config.$this->config;
538 4
		$this->add_script_imports_to_document($Config, $system_scripts.$system_imports.$scripts.$html_imports);
539 4
	}
540
}
541