diff --git a/src/Assetic/Filter/CssImportFilter.php b/src/Assetic/Filter/CssImportFilter.php index 6278f812b..30157404d 100644 --- a/src/Assetic/Filter/CssImportFilter.php +++ b/src/Assetic/Filter/CssImportFilter.php @@ -1,22 +1,29 @@ */ -class CssImportFilter extends BaseCssFilter implements DependencyExtractorInterface +class CssImportFilter extends BaseCssFilter implements HashableInterface, DependencyExtractorInterface { /** * @var mixed importFilter */ protected $importFilter; + /** + * @var string lastHash + */ + protected $lastHash; + /** * __construct * @@ -37,29 +44,29 @@ public function filterLoad(AssetInterface $asset) $sourcePath = $asset->getSourcePath(); $callback = function ($matches) use ($importFilter, $sourceRoot, $sourcePath) { - if (!$matches['url'] || null === $sourceRoot) { + if (!$matches['url'] || $sourceRoot === null) { return $matches[0]; } $importRoot = $sourceRoot; - if (false !== strpos($matches['url'], '://')) { - // absolute + // Absolute + if (strpos($matches['url'], '://') !== false) { list($importScheme, $tmp) = explode('://', $matches['url'], 2); list($importHost, $importPath) = explode('/', $tmp, 2); $importRoot = $importScheme.'://'.$importHost; } - elseif (0 === strpos($matches['url'], '//')) { - // protocol-relative + // Protocol-relative + elseif (strpos($matches['url'], '//') === 0) { list($importHost, $importPath) = explode('/', substr($matches['url'], 2), 2); $importRoot = '//'.$importHost; } - elseif ('/' == $matches['url'][0]) { - // root-relative + // Root-relative + elseif ($matches['url'][0] == '/') { $importPath = substr($matches['url'], 1); } - elseif (null !== $sourcePath) { - // document-relative + // Document-relative + elseif ($sourcePath !== null) { $importPath = $matches['url']; if ('.' != $sourceDir = dirname($sourcePath)) { $importPath = $sourceDir.'/'.$importPath; @@ -70,15 +77,15 @@ public function filterLoad(AssetInterface $asset) } $importSource = $importRoot.'/'.$importPath; - if (false !== strpos($importSource, '://') || 0 === strpos($importSource, '//')) { - $import = new HttpAsset($importSource, array($importFilter), true); + if (strpos($importSource, '://') !== false || strpos($importSource, '//') === 0) { + $import = new HttpAsset($importSource, [$importFilter], true); } - elseif ('css' != pathinfo($importPath, PATHINFO_EXTENSION) || !file_exists($importSource)) { - // ignore non-css and non-existant imports + // Ignore non-css and non-existent imports + elseif (pathinfo($importPath, PATHINFO_EXTENSION) != 'css' || !file_exists($importSource)) { return $matches[0]; } else { - $import = new FileAsset($importSource, array($importFilter), $importRoot, $importPath); + $import = new FileAsset($importSource, [$importFilter], $importRoot, $importPath); } $import->setTargetPath($sourcePath); @@ -92,7 +99,7 @@ public function filterLoad(AssetInterface $asset) do { $content = $this->filterImports($content, $callback); $hash = md5($content); - } while ($lastHash != $hash && $lastHash = $hash); + } while ($lastHash != $hash && ($lastHash = $hash)); $asset->setContent($content); } @@ -105,11 +112,84 @@ public function filterDump(AssetInterface $asset) } /** - * getChildren + * hashAsset + */ + public function hashAsset($asset, $localPath) + { + $factory = new AssetFactory($localPath); + $children = $this->getAllChildren($factory, file_get_contents($asset), dirname($asset)); + + $allFiles = []; + foreach ($children as $child) { + $allFiles[] = $child; + } + + $modified = []; + foreach ($allFiles as $file) { + $modified[] = $file->getLastModified(); + } + + return md5(implode('|', $modified)); + } + + /** + * setHash + */ + public function setHash($hash) + { + $this->lastHash = $hash; + } + + /** + * hash generated for the object + * @return string + */ + public function hash() + { + return $this->lastHash ?: serialize($this); + } + + /** + * getAllChildren loads all children recursively + */ + public function getAllChildren(AssetFactory $factory, $content, $loadPath = null) + { + $children = (new static)->getChildren($factory, $content, $loadPath); + + foreach ($children as $child) { + $childContent = file_get_contents($child->getSourceRoot().'/'.$child->getSourcePath()); + $children = array_merge($children, (new static)->getChildren($factory, $childContent, $loadPath.'/'.dirname($child->getSourcePath()))); + } + + return $children; + } + + /** + * getChildren only returns one level of children */ public function getChildren(AssetFactory $factory, $content, $loadPath = null) { - // todo - return []; + if (!$loadPath) { + return []; + } + + $children = []; + foreach (CssUtils::extractImports($content) as $reference) { + // Strict check, only allow .css imports + if (substr($reference, -4) !== '.css') { + continue; + } + + if (file_exists($file = $loadPath.'/'.$reference)) { + $coll = $factory->createAsset($file, [], ['root' => $loadPath]); + foreach ($coll as $leaf) { + $leaf->ensureFilter($this); + $children[] = $leaf; + break; + } + } + } + + return $children; } } diff --git a/src/Assetic/Filter/LessCompiler.php b/src/Assetic/Filter/LessCompiler.php index 8fa7705f1..1db6ff61d 100644 --- a/src/Assetic/Filter/LessCompiler.php +++ b/src/Assetic/Filter/LessCompiler.php @@ -17,15 +17,27 @@ */ class LessCompiler implements FilterInterface, HashableInterface, DependencyExtractorInterface { + /** + * @var array presets + */ protected $presets = []; + /** + * @var string lastHash + */ protected $lastHash; + /** + * setPresets + */ public function setPresets(array $presets) { $this->presets = $presets; } + /** + * filterLoad + */ public function filterLoad(AssetInterface $asset) { $parser = new Less_Parser(); @@ -41,10 +53,16 @@ public function filterLoad(AssetInterface $asset) $asset->setContent($parser->getCss()); } + /** + * filterDump + */ public function filterDump(AssetInterface $asset) { } + /** + * hashAsset + */ public function hashAsset($asset, $localPath) { $factory = new AssetFactory($localPath); @@ -55,21 +73,24 @@ public function hashAsset($asset, $localPath) $allFiles[] = $child; } - $modifieds = []; + $modified = []; foreach ($allFiles as $file) { - $modifieds[] = $file->getLastModified(); + $modified[] = $file->getLastModified(); } - return md5(implode('|', $modifieds)); + return md5(implode('|', $modified)); } + /** + * setHash + */ public function setHash($hash) { $this->lastHash = $hash; } /** - * Generates a hash for the object + * hash generated for the object * @return string */ public function hash() @@ -78,7 +99,7 @@ public function hash() } /** - * Load children recusive + * getChildren loads children recursively */ public function getChildren(AssetFactory $factory, $content, $loadPath = null) { diff --git a/src/Assetic/Filter/LessphpFilter.php b/src/Assetic/Filter/LessphpFilter.php index d91d2270b..defb0fae1 100644 --- a/src/Assetic/Filter/LessphpFilter.php +++ b/src/Assetic/Filter/LessphpFilter.php @@ -118,7 +118,7 @@ public function filterDump(AssetInterface $asset) public function getChildren(AssetFactory $factory, $content, $loadPath = null) { $loadPaths = $this->loadPaths; - if (null !== $loadPath) { + if ($loadPath !== null) { $loadPaths[] = $loadPath; } @@ -128,28 +128,26 @@ public function getChildren(AssetFactory $factory, $content, $loadPath = null) $children = []; foreach (LessUtils::extractImports($content) as $reference) { - if ('.css' === substr($reference, -4)) { + if (substr($reference, -4) === '.css') { // skip normal css imports // todo: skip imports with media queries continue; } - if ('.less' !== substr($reference, -5)) { + if (substr($reference, -5) !== '.less') { $reference .= '.less'; } foreach ($loadPaths as $loadPath) { if (file_exists($file = $loadPath.'/'.$reference)) { - $coll = $factory->createAsset($file, array(), array('root' => $loadPath)); + $coll = $factory->createAsset($file, [], ['root' => $loadPath]); foreach ($coll as $leaf) { $leaf->ensureFilter($this); $children[] = $leaf; - goto next_reference; + break 2; } } } - - next_reference: } return $children; diff --git a/src/Assetic/Traits/HasDeepHasher.php b/src/Assetic/Traits/HasDeepHasher.php index 677504976..3989b18ae 100644 --- a/src/Assetic/Traits/HasDeepHasher.php +++ b/src/Assetic/Traits/HasDeepHasher.php @@ -4,7 +4,7 @@ use October\Rain\Assetic\Factory\AssetFactory; /** - * Combiner helper class + * HasDeepHasher checks if imports have changed their content and busts the cache * * @package october/assetic * @author Alexey Bobkov, Samuel Georges @@ -48,7 +48,6 @@ public function getDeepHashFromAssets($assets) /** * setHashOnCombinerFilters busts the cache based on a different cache key. - * @return void */ protected function setDeepHashKeyOnFilters($hash) {