cache = $minify_cache; $this->config = $config_factory->get('advagg_css_minify.settings'); $this->advaggConfig = $config_factory->get('advagg.settings'); $this->advaggFiles = $advagg_files; $this->moduleHandler = $module_handler; } /** * Generate the css minification configuration. * * @return array * Array($options, $description, $minifiers, $functions). */ public function getConfiguration() { $description = ''; $options = [ 0 => t('Disabled'), 1 => t('Core'), 2 => t('YUI'), ]; $minifiers = [NULL, NULL, NULL]; $functions = [NULL, NULL, NULL]; // Allow for other modules to alter this list. $options_desc = [$options, $description]; $this->moduleHandler->alter('advagg_css_minify_configuration', $options_desc, $minifiers, $functions); list($options, $description) = $options_desc; return [$options, $description, $minifiers, $functions]; } /** * Loads the stylesheet and resolves all @import commands. * * Loads a stylesheet and replaces @import commands with the contents of the * imported file. Use this instead of file_get_contents when processing * stylesheets. * * The returned contents are compressed removing white space and comments only * when CSS aggregation is enabled. This optimization will not apply for * color.module enabled themes with CSS aggregation turned off. * * Note: the only reason this method is public is so color.module can call it; * it is not on the AssetOptimizerInterface, so future refactorings can make * it protected. * * @param string $file * Name of the stylesheet to be processed. * @param bool $optimize * (optional) Defines if CSS contents should be compressed or not. Not used * in AdvAgg implementation. * @param bool $reset_basepath * (optional) Used internally to facilitate recursive resolution of @import * commands. * * @return string * Contents of the stylesheet, including any resolved @import commands. */ public function loadFile($file, $optimize = NULL, $reset_basepath = TRUE) { // These statics are not cache variables, so we don't use drupal_static(). static $basepath; if ($reset_basepath) { $basepath = ''; } // Stylesheets are relative one to each other. Start by adding a base path // prefix provided by the parent stylesheet (if necessary). if ($basepath && !file_uri_scheme($file)) { $file = $basepath . '/' . $file; } // Store the parent base path to restore it later. $parent_base_path = $basepath; // Set the current base path to process possible child imports. $basepath = dirname($file); // Load the CSS stylesheet. We suppress errors because themes may specify // stylesheets in their .info.yml file that don't exist in the theme's path, // but are merely there to disable certain module CSS files. $content = ''; if ($contents = @file_get_contents($file)) { // If a BOM is found, convert the file to UTF-8, then use substr() to // remove the BOM from the result. if ($encoding = (Unicode::encodingFromBOM($contents))) { $contents = Unicode::substr(Unicode::convertToUtf8($contents, $encoding), 1); } // If no BOM, check for fallback encoding. Per CSS spec the regex is very // strict. elseif (preg_match('/^@charset "([^"]+)";/', $contents, $matches)) { if ($matches[1] !== 'utf-8' && $matches[1] !== 'UTF-8') { $contents = substr($contents, strlen($matches[0])); $contents = Unicode::convertToUtf8($contents, $matches[1]); } } $minifier = $this->config->get('minifier'); if ($file_settings = $this->config->get('file_settings')) { $file_settings = array_column($file_settings, 'minifier', 'path'); if (isset($file_settings[$file])) { $minifier = $file_settings[$file]; } } $info = $this->advaggFiles->get($file); $cid = 'css_minify:' . $minifier . ':' . $info['filename_hash']; $cid .= !empty($info['content_hash']) ? ':' . $info['content_hash'] : ''; $cached_data = $this->cache->get($cid); if (!empty($cached_data->data)) { $content = $cached_data->data; } else { if (!$minifier || $this->advaggConfig->get('cache_level') < 0) { $content = $this->processCss($contents, FALSE); } elseif ($minifier == 1) { $content = $this->processCss($contents, TRUE); } elseif ($minifier == 2) { $content = $this->processCssMin($contents); } else { $content = $this->processCssOther($contents, $minifier); } } // Cache minified data for at least 1 week. $this->cache->set($cid, $content, REQUEST_TIME + (86400 * 7), ['advagg_css', $info['filename_hash']]); } // Restore the parent base path as the file and its children are processed. $basepath = $parent_base_path; return $content; } /** * Processes the contents of a stylesheet through CSSMin for minification. * * @param string $contents * The contents of the stylesheet. * * @return string * Minified contents of the stylesheet including the imported stylesheets. */ protected function processCssMin($contents) { $contents = $this->clean($contents); if (!class_exists('CSSmin')) { include drupal_get_path('module', 'advagg_css_minify') . '/yui/CSSMin.inc'; } $cssmin = new \CSSmin(TRUE); // Minify the CSS splitting lines after 4k of text. $contents = $cssmin->run($contents, 4096); // Replaces @import commands with the actual stylesheet content. // This happens recursively but omits external files. $contents = preg_replace_callback('/@import\s*(?:url\(\s*)?[\'"]?(?![a-z]+:)(?!\/\/)([^\'"\()]+)[\'"]?\s*\)?\s*;/', [$this, 'loadNestedFile'], $contents); return $contents; } /** * Processes the contents of a stylesheet for minification. * * @param string $contents * The contents of the stylesheet. * @param string $minifier * The name of the minifier to use. * * @return string * Minified contents of the stylesheet including the imported stylesheets. */ protected function processCssOther($contents, $minifier) { $contents = $this->clean($contents); list(, , , $functions) = $this->getConfiguration(); if (isset($functions[$minifier])) { $run = $functions[$minifier]; if (function_exists($run)) { $run($contents); } } // Replaces @import commands with the actual stylesheet content. // This happens recursively but omits external files. $contents = preg_replace_callback('/@import\s*(?:url\(\s*)?[\'"]?(?![a-z]+:)(?!\/\/)([^\'"\()]+)[\'"]?\s*\)?\s*;/', [$this, 'loadNestedFile'], $contents); return $contents; } }