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

Cache   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 154
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 97.14%

Importance

Changes 0
Metric Value
dl 0
loc 154
ccs 68
cts 70
cp 0.9714
rs 10
c 0
b 0
f 0
wmc 17
lcom 1
cbo 4

5 Methods

Rating   Name   Duplication   Size   Complexity  
A rebuild_cache() 0 20 3
A rebuild_cache_optimized() 0 13 3
A rebuild_cache_other() 0 5 1
B cache_compressed_includes_files() 0 25 4
B cache_compressed_includes_files_single() 0 65 6
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\Includes;
9
use
10
	cs\Event,
11
	cs\Language,
12
	cs\Page\Includes_processing;
13
14
trait Cache {
15
	/**
16
	 * @param \cs\Config $Config
17
	 */
18 4
	protected function rebuild_cache ($Config) {
19 4
		if (!file_exists("$this->pcache_basename_path.json")) {
20 4
			list($dependencies, $includes_map) = $this->get_includes_dependencies_and_map($Config);
21 4
			$compressed_includes_map    = [];
22 4
			$not_embedded_resources_map = [];
23 4
			foreach ($includes_map as $filename_prefix => $local_includes) {
24 4
				$compressed_includes_map[$filename_prefix] = $this->cache_compressed_includes_files(
25 4
					"$this->pcache_basename_path:".str_replace('/', '+', $filename_prefix),
26
					$local_includes,
27 4
					$Config->core['vulcanization'],
28
					$not_embedded_resources_map
29
				);
30
			}
31 4
			unset($includes_map, $filename_prefix, $local_includes);
32 4
			file_put_json("$this->pcache_basename_path.json", [$dependencies, $compressed_includes_map, array_filter($not_embedded_resources_map)]);
33 4
			Event::instance()->fire('System/Page/rebuild_cache');
34 4
			$this->rebuild_cache_optimized();
35 4
			$this->rebuild_cache_other();
36
		}
37 4
	}
38 4
	protected function rebuild_cache_optimized () {
39 4
		list(, $compressed_includes_map, $preload_source) = file_get_json("$this->pcache_basename_path.json");
40 4
		$preload = [array_values($compressed_includes_map['System'])];
41 4
		foreach ($compressed_includes_map['System'] as $path) {
42 4
			if (isset($preload_source[$path])) {
43 4
				$preload[] = $preload_source[$path];
44
			}
45
		}
46 4
		unset($compressed_includes_map['System']);
47 4
		$optimized_includes = array_flip(array_merge(...array_values(array_map('array_values', $compressed_includes_map))));
48 4
		$preload            = array_merge(...$preload);
49 4
		file_put_json("$this->pcache_basename_path.optimized.json", [$optimized_includes, $preload]);
50 4
	}
51 4
	protected function rebuild_cache_other () {
52 4
		$webcomponents_js = file_get_contents(DIR.'/includes/js/WebComponents-polyfill/webcomponents-custom.min.js');
53 4
		file_put_contents(PUBLIC_CACHE.'/webcomponents.js', $webcomponents_js, LOCK_EX | FILE_BINARY);
54 4
		file_put_contents(PUBLIC_CACHE.'/webcomponents.js.hash', substr(md5($webcomponents_js), 0, 5), LOCK_EX | FILE_BINARY);
55 4
	}
56
	/**
57
	 * Creates cached version of given HTML, JS and CSS files.
58
	 * Resulting files names consist of `$filename_prefix` and extension.
59
	 *
60
	 * @param string     $target_file_path
61
	 * @param string[][] $includes                   Array of paths to files, may have keys: `css` and/or `js` and/or `html`
62
	 * @param bool       $vulcanization              Whether to put combined files separately or to make includes built-in (vulcanization)
63
	 * @param string[][] $not_embedded_resources_map Resources like images/fonts might not be embedded into resulting CSS because of big size or CSS/JS because
64
	 *                                               of CSP
65
	 *
66
	 * @return array
67
	 */
68 4
	protected function cache_compressed_includes_files ($target_file_path, $includes, $vulcanization, &$not_embedded_resources_map) {
69 4
		$local_includes = [];
70 4
		foreach ($includes as $extension => $files) {
71 4
			$not_embedded_resources = [];
72 4
			$content                = $this->cache_compressed_includes_files_single(
73
				$extension,
74
				$target_file_path,
75
				$files,
76
				$vulcanization,
77
				$not_embedded_resources
78
			);
79 4
			foreach ($not_embedded_resources as &$resource) {
80
				if (strpos($resource, '/') !== 0) {
81
					$resource = "/storage/pcache/$resource";
82
				}
83
			}
84 4
			unset($resource);
85 4
			$file_path = "$target_file_path.$extension";
86 4
			file_put_contents($file_path, $content, LOCK_EX | FILE_BINARY);
87 4
			$relative_path                              = '/storage/pcache/'.basename($file_path).'?'.substr(md5($content), 0, 5);
88 4
			$local_includes[$extension]                 = $relative_path;
89 4
			$not_embedded_resources_map[$relative_path] = $not_embedded_resources;
90
		}
91 4
		return $local_includes;
92
	}
93
	/**
94
	 * @param string   $extension
95
	 * @param string   $target_file_path
96
	 * @param string[] $files
97
	 * @param bool     $vulcanization          Whether to put combined files separately or to make includes built-in (vulcanization)
98
	 * @param string[] $not_embedded_resources Resources like images/fonts might not be embedded into resulting CSS because of big size or CSS/JS because of CSP
99
	 *
100
	 * @return string
101
	 */
102 4
	protected function cache_compressed_includes_files_single ($extension, $target_file_path, $files, $vulcanization, &$not_embedded_resources) {
103 4
		$content = '';
104
		switch ($extension) {
105
			/**
106
			 * Insert external elements into resulting css file.
107
			 * It is needed, because those files will not be copied into new destination of resulting css file.
108
			 */
109 4
			case 'css':
110
				/**
111
				 * @param string $content
112
				 * @param string $file
113
				 *
114
				 * @return string
115
				 */
116
				$callback = function ($content, $file) use (&$not_embedded_resources) {
117 4
					return $content.Includes_processing::css(file_get_contents($file), $file, $not_embedded_resources);
118 4
				};
119 4
				break;
120
			/**
121
			 * Combine css and js files for Web Component into resulting files in order to optimize loading process
122
			 */
123 4
			case 'html':
124
				/**
125
				 * For CSP-compatible HTML files we need to know destination to put there additional JS/CSS files
126
				 *
127
				 * @param string $content
128
				 * @param string $file
129
				 *
130
				 * @return string
131
				 */
132
				$callback = function ($content, $file) use (&$not_embedded_resources) {
133 4
					return $content.Includes_processing::html(
134
						file_get_contents($file),
135
						$file,
136 4
						'',
137 4
						true,
138
						$not_embedded_resources
139
					);
140 4
				};
141 4
				break;
142 4
			case 'js':
143
				/**
144
				 * @param string $content
145
				 * @param string $file
146
				 *
147
				 * @return string
148
				 */
149 4
				$callback = function ($content, $file) {
150 4
					return $content.Includes_processing::js(file_get_contents($file));
151 4
				};
152 4
				if (substr($target_file_path, -7) == ':System') {
153
					// Hack: BOM is a hack for Chromium that have broken utf-8 detection for `Link: rel=preload; as=script`
154
					// TODO: Remove workaround when fixed upstream
155 4
					$content = "\xEF\xBB\xBFwindow.cs={Language:"._json_encode(Language::instance()).'};';
156 4
					$content .= 'window.requirejs={paths:'._json_encode($this->get_requirejs_paths()).'};';
157
				}
158
		}
159
		/** @noinspection PhpUndefinedVariableInspection */
160 4
		$content = array_reduce($files, $callback, $content);
161 4
		if ($extension == 'html') {
162 4
			$file_path = "$target_file_path-$extension";
163 4
			$content   = Includes_processing::html($content, $file_path, $file_path, $vulcanization);
164
		}
165 4
		return $content;
166
	}
167
}
168