\n"; const JS_IMPORT_DIRECTIVE = "\n"; const JS_DEFER_IMPORT_DIRECTIVE = "\n"; const GET_CSS_MODULE_ACTION = "index.php?module=Proxy&action=getCss"; const GET_CORE_JS_MODULE_ACTION = "index.php?module=Proxy&action=getCoreJs"; const GET_NON_CORE_JS_MODULE_ACTION = "index.php?module=Proxy&action=getNonCoreJs"; const GET_JS_UMD_MODULE_ACTION = "index.php?module=Proxy&action=getUmdJs&chunk="; /** * @var UIAssetCacheBuster */ private $cacheBuster; /** * @var UIAssetFetcher */ private $minimalStylesheetFetcher; /** * @var Theme */ private $theme; public function __construct() { $this->cacheBuster = UIAssetCacheBuster::getInstance(); $this->minimalStylesheetFetcher = new StaticUIAssetFetcher(array(), array(), $this->theme); $theme = Manager::getInstance()->getThemeEnabled(); if (!empty($theme)) { $this->theme = new Theme(); } } /** * @inheritDoc * @return AssetManager */ public static function getInstance() { $assetManager = parent::getInstance(); /** * Triggered when creating an instance of the asset manager. Lets you overwrite the * asset manager behavior. * * @param AssetManager &$assetManager * * @ignore * This event is not a public event since we don't want to make the asset manager itself public * API */ Piwik::postEvent('AssetManager.makeNewAssetManagerObject', array(&$assetManager)); return $assetManager; } /** * @param UIAssetCacheBuster $cacheBuster */ public function setCacheBuster($cacheBuster) { $this->cacheBuster = $cacheBuster; } /** * @param UIAssetFetcher $minimalStylesheetFetcher */ public function setMinimalStylesheetFetcher($minimalStylesheetFetcher) { $this->minimalStylesheetFetcher = $minimalStylesheetFetcher; } /** * @param Theme $theme */ public function setTheme($theme) { $this->theme = $theme; } /** * Return CSS file inclusion directive(s) using the markup * * @return string */ public function getCssInclusionDirective() { return sprintf(self::CSS_IMPORT_DIRECTIVE, self::GET_CSS_MODULE_ACTION); } /** * Return JS file inclusion directive(s) using the markup "; if ($this->isMergedAssetsDisabled()) { $this->getMergedCoreJSAsset()->delete(); $this->getMergedNonCoreJSAsset()->delete(); $result .= $this->getIndividualCoreAndNonCoreJsIncludes(); } else { $result .= sprintf(self::JS_IMPORT_DIRECTIVE, self::GET_CORE_JS_MODULE_ACTION); $result .= sprintf(self::JS_IMPORT_DIRECTIVE, self::GET_NON_CORE_JS_MODULE_ACTION); $result .= $this->getPluginUmdChunks(); } return $result; } private function getPluginUmdChunks() { $fetcher = $this->getPluginUmdJScriptFetcher(); $chunks = $fetcher->getChunkFiles(); $result = ''; foreach ($chunks as $chunk) { $src = self::GET_JS_UMD_MODULE_ACTION . urlencode($chunk->getChunkName()); $result .= sprintf(self::JS_DEFER_IMPORT_DIRECTIVE, $src); } return $result; } /** * Return the base.less compiled to css * * @return UIAsset */ public function getCompiledBaseCss() { $mergedAsset = new InMemoryUIAsset(); $assetMerger = new StylesheetUIAssetMerger($mergedAsset, $this->minimalStylesheetFetcher, $this->cacheBuster); $assetMerger->generateFile(); return $mergedAsset; } /** * Return the css merged file absolute location. * If there is none, the generation process will be triggered. * * @return UIAsset */ public function getMergedStylesheet() { $mergedAsset = $this->getMergedStylesheetAsset(); $assetFetcher = new StylesheetUIAssetFetcher(Manager::getInstance()->getLoadedPluginsName(), $this->theme); $assetMerger = new StylesheetUIAssetMerger($mergedAsset, $assetFetcher, $this->cacheBuster); $assetMerger->generateFile(); return $mergedAsset; } /** * Return the core js merged file absolute location. * If there is none, the generation process will be triggered. * * @return UIAsset */ public function getMergedCoreJavaScript() { return $this->getMergedJavascript($this->getCoreJScriptFetcher(), $this->getMergedCoreJSAsset()); } /** * Return the non core js merged file absolute location. * If there is none, the generation process will be triggered. * * @return UIAsset */ public function getMergedNonCoreJavaScript() { return $this->getMergedJavascript($this->getNonCoreJScriptFetcher(), $this->getMergedNonCoreJSAsset()); } /** * Return a chunk JS merged file absolute location. * If there is none, the generation process will be triggered. * * @param string $chunk The name of the chunk. Will either be a plugin name or an integer. * @return UIAsset */ public function getMergedJavaScriptChunk($chunk) { $assetFetcher = $this->getPluginUmdJScriptFetcher($chunk); $outputFile = $assetFetcher->getRequestedChunkOutputFile(); return $this->getMergedJavascript($assetFetcher, $this->getMergedUIAsset($outputFile)); } /** * @param boolean|"all" $core * @return string[] */ public function getLoadedPlugins($core) { $loadedPlugins = array(); foreach (Manager::getInstance()->getPluginsLoadedAndActivated() as $plugin) { $pluginName = $plugin->getPluginName(); $pluginIsCore = Manager::getInstance()->isPluginBundledWithCore($pluginName); if ($core === 'all' || ($pluginIsCore && $core) || (!$pluginIsCore && !$core)) { $loadedPlugins[] = $pluginName; } } return $loadedPlugins; } /** * Remove previous merged assets */ public function removeMergedAssets($pluginName = false) { $assetsToRemove = array($this->getMergedStylesheetAsset()); if ($pluginName) { if ($this->pluginContainsJScriptAssets($pluginName)) { if (Manager::getInstance()->isPluginBundledWithCore($pluginName)) { $assetsToRemove[] = $this->getMergedCoreJSAsset(); } else { $assetsToRemove[] = $this->getMergedNonCoreJSAsset(); } $assetFetcher = $this->getPluginUmdJScriptFetcher(); foreach ($assetFetcher->getChunkFiles() as $chunk) { $files = $chunk->getFiles(); $foundInChunk = false; foreach ($files as $file) { if (strpos($file, "/$pluginName.umd.") !== false) { $foundInChunk = true; } } if ($foundInChunk) { $outputFile = $chunk->getOutputFile(); $asset = $this->getMergedUIAsset($outputFile); if ($asset->exists()) { $assetsToRemove[] = $asset; } break; } } } } else { $assetsToRemove[] = $this->getMergedCoreJSAsset(); $assetsToRemove[] = $this->getMergedNonCoreJSAsset(); $assetFetcher = $this->getPluginUmdJScriptFetcher(); foreach ($assetFetcher->getChunkFiles() as $chunk) { $outputFile = $chunk->getOutputFile(); $asset = $this->getMergedUIAsset($outputFile); if ($asset->exists()) { $assetsToRemove[] = $asset; } } } $this->removeAssets($assetsToRemove); } /** * Check if the merged file directory exists and is writable. * * @return string The directory location * @throws Exception if directory is not writable. */ public function getAssetDirectory() { $mergedFileDirectory = StaticContainer::get('path.tmp') . '/assets'; if (!is_dir($mergedFileDirectory)) { Filesystem::mkdir($mergedFileDirectory); } if (!is_writable($mergedFileDirectory)) { throw new Exception("Directory " . $mergedFileDirectory . " has to be writable."); } return $mergedFileDirectory; } /** * Return the global option disable_merged_assets * * @return boolean */ public function isMergedAssetsDisabled() { if (Config::getInstance()->Development['disable_merged_assets'] == 1) { return true; } if (isset($_GET['disable_merged_assets']) && $_GET['disable_merged_assets'] == 1) { return true; } return false; } /** * @param UIAssetFetcher $assetFetcher * @param UIAsset $mergedAsset * @return UIAsset */ private function getMergedJavascript($assetFetcher, $mergedAsset) { $assetMerger = new JScriptUIAssetMerger($mergedAsset, $assetFetcher, $this->cacheBuster); $assetMerger->generateFile(); return $mergedAsset; } /** * Return individual JS file inclusion directive(s) using the markup