PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 1.3.1
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v1.3.1
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / AssetManager.php
matomo / app / core Last commit date
API 6 years ago Access 6 years ago Application 6 years ago Archive 6 years ago ArchiveProcessor 6 years ago Archiver 6 years ago AssetManager 6 years ago Auth 6 years ago Category 6 years ago CliMulti 6 years ago Columns 6 years ago Composer 6 years ago Concurrency 6 years ago Config 6 years ago Container 6 years ago CronArchive 6 years ago DataAccess 5 years ago DataFiles 6 years ago DataTable 6 years ago Db 6 years ago DeviceDetector 5 years ago Email 6 years ago Exception 6 years ago Http 6 years ago Intl 6 years ago Mail 6 years ago Measurable 6 years ago Menu 6 years ago Metrics 6 years ago Notification 6 years ago Period 6 years ago Plugin 6 years ago ProfessionalServices 6 years ago Report 6 years ago ReportRenderer 6 years ago Scheduler 6 years ago Segment 6 years ago Session 6 years ago Settings 6 years ago Tracker 5 years ago Translation 6 years ago UpdateCheck 6 years ago Updater 6 years ago Updates 6 years ago Validators 6 years ago View 6 years ago ViewDataTable 6 years ago Visualization 6 years ago Widget 6 years ago .htaccess 6 years ago Access.php 6 years ago Archive.php 6 years ago ArchiveProcessor.php 6 years ago AssetManager.php 6 years ago Auth.php 6 years ago BaseFactory.php 6 years ago Cache.php 6 years ago CacheId.php 6 years ago CliMulti.php 6 years ago Common.php 6 years ago Config.php 6 years ago Console.php 6 years ago Context.php 6 years ago Cookie.php 5 years ago CronArchive.php 5 years ago DataArray.php 6 years ago DataTable.php 6 years ago Date.php 6 years ago Db.php 6 years ago DbHelper.php 6 years ago Development.php 6 years ago DeviceDetectorFactory.php 6 years ago ErrorHandler.php 6 years ago EventDispatcher.php 6 years ago ExceptionHandler.php 6 years ago FileIntegrity.php 6 years ago Filechecks.php 6 years ago Filesystem.php 6 years ago FrontController.php 6 years ago Http.php 6 years ago IP.php 6 years ago Log.php 6 years ago LogDeleter.php 6 years ago Mail.php 6 years ago Metrics.php 6 years ago MetricsFormatter.php 6 years ago Nonce.php 5 years ago Notification.php 6 years ago NumberFormatter.php 6 years ago Option.php 5 years ago Period.php 6 years ago Piwik.php 6 years ago Plugin.php 6 years ago Profiler.php 6 years ago ProxyHeaders.php 6 years ago ProxyHttp.php 6 years ago QuickForm2.php 6 years ago RankingQuery.php 6 years ago Registry.php 6 years ago ReportRenderer.php 6 years ago ScheduledTask.php 6 years ago Segment.php 6 years ago Sequence.php 6 years ago Session.php 6 years ago SettingsPiwik.php 6 years ago SettingsServer.php 6 years ago Singleton.php 6 years ago Site.php 6 years ago TCPDF.php 6 years ago TaskScheduler.php 6 years ago Theme.php 6 years ago Timer.php 6 years ago Tracker.php 6 years ago Translate.php 6 years ago Twig.php 6 years ago Unzip.php 6 years ago UpdateCheck.php 6 years ago Updater.php 6 years ago Updates.php 6 years ago Url.php 6 years ago UrlHelper.php 6 years ago Version.php 5 years ago View.php 6 years ago bootstrap.php 6 years ago dispatch.php 6 years ago testMinimumPhpVersion.php 6 years ago
AssetManager.php
449 lines
1 <?php
2 /**
3 * Piwik - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 *
8 */
9 namespace Piwik;
10
11 use Exception;
12 use Piwik\AssetManager\UIAsset;
13 use Piwik\AssetManager\UIAsset\InMemoryUIAsset;
14 use Piwik\AssetManager\UIAsset\OnDiskUIAsset;
15 use Piwik\AssetManager\UIAssetCacheBuster;
16 use Piwik\AssetManager\UIAssetFetcher\JScriptUIAssetFetcher;
17 use Piwik\AssetManager\UIAssetFetcher\StaticUIAssetFetcher;
18 use Piwik\AssetManager\UIAssetFetcher\StylesheetUIAssetFetcher;
19 use Piwik\AssetManager\UIAssetFetcher;
20 use Piwik\AssetManager\UIAssetMerger\JScriptUIAssetMerger;
21 use Piwik\AssetManager\UIAssetMerger\StylesheetUIAssetMerger;
22 use Piwik\Container\StaticContainer;
23 use Piwik\Plugin\Manager;
24
25 /**
26 * AssetManager is the class used to manage the inclusion of UI assets:
27 * JavaScript and CSS files.
28 *
29 * It performs the following actions:
30 * - Identifies required assets
31 * - Includes assets in the rendered HTML page
32 * - Manages asset merging and minifying
33 * - Manages server-side cache
34 *
35 * Whether assets are included individually or as merged files is defined by
36 * the global option 'disable_merged_assets'. See the documentation in the global
37 * config for more information.
38 */
39 class AssetManager extends Singleton
40 {
41 const MERGED_CSS_FILE = "asset_manager_global_css.css";
42 const MERGED_CORE_JS_FILE = "asset_manager_core_js.js";
43 const MERGED_NON_CORE_JS_FILE = "asset_manager_non_core_js.js";
44
45 const CSS_IMPORT_DIRECTIVE = "<link rel=\"stylesheet\" type=\"text/css\" href=\"%s\" />\n";
46 const JS_IMPORT_DIRECTIVE = "<script type=\"text/javascript\" src=\"%s\"></script>\n";
47 const GET_CSS_MODULE_ACTION = "index.php?module=Proxy&action=getCss";
48 const GET_CORE_JS_MODULE_ACTION = "index.php?module=Proxy&action=getCoreJs";
49 const GET_NON_CORE_JS_MODULE_ACTION = "index.php?module=Proxy&action=getNonCoreJs";
50
51 /**
52 * @var UIAssetCacheBuster
53 */
54 private $cacheBuster;
55
56 /**
57 * @var UIAssetFetcher
58 */
59 private $minimalStylesheetFetcher;
60
61 /**
62 * @var Theme
63 */
64 private $theme;
65
66 public function __construct()
67 {
68 $this->cacheBuster = UIAssetCacheBuster::getInstance();
69
70 $this->minimalStylesheetFetcher = new StaticUIAssetFetcher(array(), array(), $this->theme);
71
72 $theme = Manager::getInstance()->getThemeEnabled();
73 if (!empty($theme)) {
74 $this->theme = new Theme();
75 }
76 }
77
78 /**
79 * @inheritDoc
80 * @return AssetManager
81 */
82 public static function getInstance()
83 {
84 $assetManager = parent::getInstance();
85
86 /**
87 * Triggered when creating an instance of the asset manager. Lets you overwite the
88 * asset manager behavior.
89 *
90 * @param AssetManager &$assetManager
91 *
92 * @ignore
93 * This event is not a public event since we don't want to make the asset manager itself public
94 * API
95 */
96 Piwik::postEvent('AssetManager.makeNewAssetManagerObject', array(&$assetManager));
97
98 return $assetManager;
99 }
100
101 /**
102 * @param UIAssetCacheBuster $cacheBuster
103 */
104 public function setCacheBuster($cacheBuster)
105 {
106 $this->cacheBuster = $cacheBuster;
107 }
108
109 /**
110 * @param UIAssetFetcher $minimalStylesheetFetcher
111 */
112 public function setMinimalStylesheetFetcher($minimalStylesheetFetcher)
113 {
114 $this->minimalStylesheetFetcher = $minimalStylesheetFetcher;
115 }
116
117 /**
118 * @param Theme $theme
119 */
120 public function setTheme($theme)
121 {
122 $this->theme = $theme;
123 }
124
125 /**
126 * Return CSS file inclusion directive(s) using the markup <link>
127 *
128 * @return string
129 */
130 public function getCssInclusionDirective()
131 {
132 return sprintf(self::CSS_IMPORT_DIRECTIVE, self::GET_CSS_MODULE_ACTION);
133 }
134
135 /**
136 * Return JS file inclusion directive(s) using the markup <script>
137 *
138 * @return string
139 */
140 public function getJsInclusionDirective()
141 {
142 $result = "<script type=\"text/javascript\">\n" . Translate::getJavascriptTranslations() . "\n</script>";
143
144 if ($this->isMergedAssetsDisabled()) {
145 $this->getMergedCoreJSAsset()->delete();
146 $this->getMergedNonCoreJSAsset()->delete();
147
148 $result .= $this->getIndividualCoreAndNonCoreJsIncludes();
149 } else {
150 $result .= sprintf(self::JS_IMPORT_DIRECTIVE, self::GET_CORE_JS_MODULE_ACTION);
151 $result .= sprintf(self::JS_IMPORT_DIRECTIVE, self::GET_NON_CORE_JS_MODULE_ACTION);
152 }
153
154 return $result;
155 }
156
157 /**
158 * Return the base.less compiled to css
159 *
160 * @return UIAsset
161 */
162 public function getCompiledBaseCss()
163 {
164 $mergedAsset = new InMemoryUIAsset();
165
166 $assetMerger = new StylesheetUIAssetMerger($mergedAsset, $this->minimalStylesheetFetcher, $this->cacheBuster);
167
168 $assetMerger->generateFile();
169
170 return $mergedAsset;
171 }
172
173 /**
174 * Return the css merged file absolute location.
175 * If there is none, the generation process will be triggered.
176 *
177 * @return UIAsset
178 */
179 public function getMergedStylesheet()
180 {
181 $mergedAsset = $this->getMergedStylesheetAsset();
182
183 $assetFetcher = new StylesheetUIAssetFetcher(Manager::getInstance()->getLoadedPluginsName(), $this->theme);
184
185 $assetMerger = new StylesheetUIAssetMerger($mergedAsset, $assetFetcher, $this->cacheBuster);
186
187 $assetMerger->generateFile();
188
189 return $mergedAsset;
190 }
191
192 /**
193 * Return the core js merged file absolute location.
194 * If there is none, the generation process will be triggered.
195 *
196 * @return UIAsset
197 */
198 public function getMergedCoreJavaScript()
199 {
200 return $this->getMergedJavascript($this->getCoreJScriptFetcher(), $this->getMergedCoreJSAsset());
201 }
202
203 /**
204 * Return the non core js merged file absolute location.
205 * If there is none, the generation process will be triggered.
206 *
207 * @return UIAsset
208 */
209 public function getMergedNonCoreJavaScript()
210 {
211 return $this->getMergedJavascript($this->getNonCoreJScriptFetcher(), $this->getMergedNonCoreJSAsset());
212 }
213
214 /**
215 * @param boolean $core
216 * @return string[]
217 */
218 public function getLoadedPlugins($core)
219 {
220 $loadedPlugins = array();
221
222 foreach (Manager::getInstance()->getPluginsLoadedAndActivated() as $plugin) {
223 $pluginName = $plugin->getPluginName();
224 $pluginIsCore = Manager::getInstance()->isPluginBundledWithCore($pluginName);
225
226 if (($pluginIsCore && $core) || (!$pluginIsCore && !$core)) {
227 $loadedPlugins[] = $pluginName;
228 }
229 }
230
231 return $loadedPlugins;
232 }
233
234 /**
235 * Remove previous merged assets
236 */
237 public function removeMergedAssets($pluginName = false)
238 {
239 $assetsToRemove = array($this->getMergedStylesheetAsset());
240
241 if ($pluginName) {
242 if ($this->pluginContainsJScriptAssets($pluginName)) {
243 if (Manager::getInstance()->isPluginBundledWithCore($pluginName)) {
244 $assetsToRemove[] = $this->getMergedCoreJSAsset();
245 } else {
246 $assetsToRemove[] = $this->getMergedNonCoreJSAsset();
247 }
248 }
249 } else {
250 $assetsToRemove[] = $this->getMergedCoreJSAsset();
251 $assetsToRemove[] = $this->getMergedNonCoreJSAsset();
252 }
253
254 $this->removeAssets($assetsToRemove);
255 }
256
257 /**
258 * Check if the merged file directory exists and is writable.
259 *
260 * @return string The directory location
261 * @throws Exception if directory is not writable.
262 */
263 public function getAssetDirectory()
264 {
265 $mergedFileDirectory = StaticContainer::get('path.tmp') . '/assets';
266
267 if (!is_dir($mergedFileDirectory)) {
268 Filesystem::mkdir($mergedFileDirectory);
269 }
270
271 if (!is_writable($mergedFileDirectory)) {
272 throw new Exception("Directory " . $mergedFileDirectory . " has to be writable.");
273 }
274
275 return $mergedFileDirectory;
276 }
277
278 /**
279 * Return the global option disable_merged_assets
280 *
281 * @return boolean
282 */
283 public function isMergedAssetsDisabled()
284 {
285 if (Config::getInstance()->Development['disable_merged_assets'] == 1) {
286 return true;
287 }
288
289 if (isset($_GET['disable_merged_assets']) && $_GET['disable_merged_assets'] == 1) {
290 return true;
291 }
292
293 return false;
294 }
295
296 /**
297 * @param UIAssetFetcher $assetFetcher
298 * @param UIAsset $mergedAsset
299 * @return UIAsset
300 */
301 private function getMergedJavascript($assetFetcher, $mergedAsset)
302 {
303 $assetMerger = new JScriptUIAssetMerger($mergedAsset, $assetFetcher, $this->cacheBuster);
304
305 $assetMerger->generateFile();
306
307 return $mergedAsset;
308 }
309
310 /**
311 * Return individual JS file inclusion directive(s) using the markup <script>
312 *
313 * @return string
314 */
315 protected function getIndividualCoreAndNonCoreJsIncludes()
316 {
317 return
318 $this->getIndividualJsIncludesFromAssetFetcher($this->getCoreJScriptFetcher()) .
319 $this->getIndividualJsIncludesFromAssetFetcher($this->getNonCoreJScriptFetcher());
320 }
321
322 /**
323 * @param UIAssetFetcher $assetFetcher
324 * @return string
325 */
326 protected function getIndividualJsIncludesFromAssetFetcher($assetFetcher)
327 {
328 $jsIncludeString = '';
329
330 $assets = $assetFetcher->getCatalog()->getAssets();
331
332 foreach ($assets as $jsFile) {
333 $jsFile->validateFile();
334 $jsIncludeString = $jsIncludeString . sprintf(self::JS_IMPORT_DIRECTIVE, $jsFile->getRelativeLocation());
335 }
336
337 return $jsIncludeString;
338 }
339
340 private function getCoreJScriptFetcher()
341 {
342 return new JScriptUIAssetFetcher($this->getLoadedPlugins(true), $this->theme);
343 }
344
345 protected function getNonCoreJScriptFetcher()
346 {
347 return new JScriptUIAssetFetcher($this->getLoadedPlugins(false), $this->theme);
348 }
349
350 /**
351 * @param string $pluginName
352 * @return boolean
353 */
354 private function pluginContainsJScriptAssets($pluginName)
355 {
356 $fetcher = new JScriptUIAssetFetcher(array($pluginName), $this->theme);
357
358 try {
359 $assets = $fetcher->getCatalog()->getAssets();
360 } catch (\Exception $e) {
361 // This can happen when a plugin is not valid (eg. Piwik 1.x format)
362 // When posting the event to the plugin, it returns an exception "Plugin has not been loaded"
363 return false;
364 }
365
366 $pluginManager = Manager::getInstance();
367 $plugin = $pluginManager->getLoadedPlugin($pluginName);
368
369 if ($plugin->isTheme()) {
370 $theme = $pluginManager->getTheme($pluginName);
371
372 $javaScriptFiles = $theme->getJavaScriptFiles();
373
374 if (!empty($javaScriptFiles)) {
375 $assets = array_merge($assets, $javaScriptFiles);
376 }
377 }
378
379 return !empty($assets);
380 }
381
382 /**
383 * @param UIAsset[] $uiAssets
384 */
385 public function removeAssets($uiAssets)
386 {
387 foreach ($uiAssets as $uiAsset) {
388 $uiAsset->delete();
389 }
390 }
391
392 /**
393 * @return UIAsset
394 */
395 public function getMergedStylesheetAsset()
396 {
397 return $this->getMergedUIAsset(self::MERGED_CSS_FILE);
398 }
399
400 /**
401 * @return UIAsset
402 */
403 private function getMergedCoreJSAsset()
404 {
405 return $this->getMergedUIAsset(self::MERGED_CORE_JS_FILE);
406 }
407
408 /**
409 * @return UIAsset
410 */
411 protected function getMergedNonCoreJSAsset()
412 {
413 return $this->getMergedUIAsset(self::MERGED_NON_CORE_JS_FILE);
414 }
415
416 /**
417 * @param string $fileName
418 * @return UIAsset
419 */
420 private function getMergedUIAsset($fileName)
421 {
422 return new OnDiskUIAsset($this->getAssetDirectory(), $fileName);
423 }
424
425 public static function compileCustomStylesheets($files)
426 {
427 $assetManager = new AssetManager();
428
429 $fetcher = new StaticUIAssetFetcher($files, $priorityOrder = array(), $theme = null);
430
431 $assetManager->setMinimalStylesheetFetcher($fetcher);
432
433 return $assetManager->getCompiledBaseCss()->getContent();
434 }
435
436 public static function compileCustomJs($files)
437 {
438 $mergedAsset = new InMemoryUIAsset();
439 $fetcher = new StaticUIAssetFetcher($files, $priorityOrder = array(), $theme = null);
440
441 $cacheBuster = UIAssetCacheBuster::getInstance();
442
443 $assetMerger = new JScriptUIAssetMerger($mergedAsset, $fetcher, $cacheBuster);
444 $assetMerger->generateFile();
445
446 return $mergedAsset->getContent();
447 }
448 }
449