Completed
Push — master ( 1c948d...3791fe )
by Nazar
04:21
created

Cache::rebuild_cache_other()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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