Completed
Push — master ( e59b98...2a95ca )
by Nazar
03:53
created

Cache::rebuild_cache()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 15

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 3
eloc 15
nc 3
nop 1
dl 0
loc 19
rs 9.4285
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);
1 ignored issue
show
Bug introduced by
It seems like get_includes_dependencies_and_map() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
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
		}
36
	}
37
	protected function rebuild_cache_optimized () {
38
		list(, $compressed_includes_map, $preload_source) = file_get_json("$this->pcache_basename_path.json");
39
		$preload = [array_values($compressed_includes_map['System'])];
40
		foreach ($compressed_includes_map['System'] as $path) {
41
			if (isset($preload_source[$path])) {
42
				$preload[] = $preload_source[$path];
43
			}
44
		}
45
		unset($compressed_includes_map['System']);
46
		$optimized_includes = array_flip(array_merge(...array_values(array_map('array_values', $compressed_includes_map))));
47
		$preload            = array_merge(...$preload);
48
		file_put_json("$this->pcache_basename_path.optimized.json", [$optimized_includes, $preload]);
49
	}
50
	/**
51
	 * Creates cached version of given HTML, JS and CSS files.
52
	 * Resulting files names consist of `$filename_prefix` and extension.
53
	 *
54
	 * @param string     $target_file_path
55
	 * @param string[][] $includes                   Array of paths to files, may have keys: `css` and/or `js` and/or `html`
56
	 * @param bool       $vulcanization              Whether to put combined files separately or to make includes built-in (vulcanization)
57
	 * @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
58
	 *                                               of CSP
59
	 *
60
	 * @return array
61
	 */
62
	protected function cache_compressed_includes_files ($target_file_path, $includes, $vulcanization, &$not_embedded_resources_map) {
63
		$local_includes = [];
64
		foreach ($includes as $extension => $files) {
65
			$not_embedded_resources = [];
66
			$content                = $this->cache_compressed_includes_files_single(
67
				$extension,
68
				$target_file_path,
69
				$files,
70
				$vulcanization,
71
				$not_embedded_resources
72
			);
73
			foreach ($not_embedded_resources as &$resource) {
74
				if (strpos($resource, '/') !== 0) {
75
					$resource = "/storage/pcache/$resource";
76
				}
77
			}
78
			unset($resource);
79
			$file_path = "$target_file_path.$extension";
80
			file_put_contents($file_path, gzencode($content, 9), LOCK_EX | FILE_BINARY);
81
			$relative_path                              = 'storage/pcache/'.basename($file_path).'?'.substr(md5($content), 0, 5);
82
			$local_includes[$extension]                 = $relative_path;
83
			$not_embedded_resources_map[$relative_path] = $not_embedded_resources;
84
		}
85
		return $local_includes;
86
	}
87
	/**
88
	 * @param string   $extension
89
	 * @param string   $target_file_path
90
	 * @param string[] $files
91
	 * @param bool     $vulcanization          Whether to put combined files separately or to make includes built-in (vulcanization)
92
	 * @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
93
	 *
94
	 * @return mixed
95
	 */
96
	protected function cache_compressed_includes_files_single ($extension, $target_file_path, $files, $vulcanization, &$not_embedded_resources) {
97
		$content = '';
98
		switch ($extension) {
99
			/**
100
			 * Insert external elements into resulting css file.
101
			 * It is needed, because those files will not be copied into new destination of resulting css file.
102
			 */
103
			case 'css':
104
				/**
105
				 * @param string $content
106
				 * @param string $file
107
				 *
108
				 * @return string
109
				 */
110
				$callback = function ($content, $file) use (&$not_embedded_resources) {
111
					return $content.Includes_processing::css(file_get_contents($file), $file, $not_embedded_resources);
112
				};
113
				break;
114
			/**
115
			 * Combine css and js files for Web Component into resulting files in order to optimize loading process
116
			 */
117
			case 'html':
118
				/**
119
				 * For CSP-compatible HTML files we need to know destination to put there additional JS/CSS files
120
				 *
121
				 * @param string $content
122
				 * @param string $file
123
				 *
124
				 * @return string
125
				 */
126
				$callback = function ($content, $file) use ($target_file_path, $vulcanization, &$not_embedded_resources) {
127
					$base_target_file_path = "$target_file_path-".basename($file).'+'.substr(md5($file), 0, 5);
128
					return $content.Includes_processing::html(
129
						file_get_contents($file),
130
						$file,
131
						$base_target_file_path,
132
						$vulcanization,
133
						$not_embedded_resources
134
					);
135
				};
136
				break;
137
			case 'js':
138
				/**
139
				 * @param string $content
140
				 * @param string $file
141
				 *
142
				 * @return string
143
				 */
144
				$callback = function ($content, $file) {
145
					return $content.Includes_processing::js(file_get_contents($file));
146
				};
147
				if (substr($target_file_path, -7) == ':System') {
148
					$content = 'window.cs={Language:'._json_encode(Language::instance()).'};';
149
					$content .= 'window.requirejs={paths:'._json_encode($this->get_requirejs_paths()).'};';
150
				}
151
		}
152
		/** @noinspection PhpUndefinedVariableInspection */
153
		return array_reduce($files, $callback, $content);
154
	}
155
}
156