1<?php 2 3/* 4 * This file is part of the Assetic package, an OpenSky project. 5 * 6 * (c) 2010-2015 OpenSky Project Inc 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Assetic\Filter; 13 14use Assetic\Factory\AssetFactory; 15use Assetic\Asset\AssetInterface; 16use Assetic\Filter\DependencyExtractorInterface; 17use Assetic\Util\CssUtils; 18 19/** 20 * Compiles Sass to CSS. 21 * 22 * @author Mikey Clarke <mikey.clarke@me.com> 23 */ 24class SassphpFilter implements DependencyExtractorInterface 25{ 26 private $includePaths = array(); 27 private $outputStyle; 28 29 public function filterLoad(AssetInterface $asset) 30 { 31 $sass = new \Sass(); 32 33 $includePaths = array_merge( 34 array($asset->getSourceDirectory()), 35 $this->includePaths 36 ); 37 $sass->setIncludePath(implode(':', $includePaths)); 38 39 if ($this->outputStyle) { 40 $sass->setStyle($this->outputStyle); 41 } 42 43 $css = $sass->compile($asset->getContent()); 44 45 $asset->setContent($css); 46 } 47 48 public function filterDump(AssetInterface $asset) 49 { 50 } 51 52 public function setOutputStyle($outputStyle) 53 { 54 $this->outputStyle = $outputStyle; 55 } 56 57 public function setIncludePaths(array $paths) 58 { 59 $this->includePaths = $paths; 60 } 61 62 public function addIncludePath($path) 63 { 64 $this->includePaths[] = $path; 65 } 66 67 public function getChildren(AssetFactory $factory, $content, $loadPath = null) 68 { 69 $children = array(); 70 71 $includePaths = $this->includePaths; 72 if (null !== $loadPath && !in_array($loadPath, $includePaths)) { 73 array_unshift($includePaths, $loadPath); 74 } 75 76 if (empty($includePaths)) { 77 return $children; 78 } 79 80 foreach (CssUtils::extractImports($content) as $reference) { 81 if ('.css' === substr($reference, -4)) { 82 continue; 83 } 84 85 // the reference may or may not have an extension or be a partial 86 if (pathinfo($reference, PATHINFO_EXTENSION)) { 87 $needles = array( 88 $reference, 89 $this->partialize($reference), 90 ); 91 } else { 92 $needles = array( 93 $reference . '.scss', 94 $this->partialize($reference) . '.scss', 95 ); 96 } 97 98 foreach ($includePaths as $includePath) { 99 foreach ($needles as $needle) { 100 if (file_exists($file = $includePath . '/' . $needle)) { 101 $child = $factory->createAsset($file, array(), array('root' => $includePath)); 102 $children[] = $child; 103 $child->load(); 104 $children = array_merge( 105 $children, 106 $this->getChildren($factory, $child->getContent(), $includePath) 107 ); 108 } 109 } 110 } 111 } 112 113 return $children; 114 } 115 116 private function partialize($reference) 117 { 118 $parts = pathinfo($reference); 119 120 if ('.' === $parts['dirname']) { 121 $partial = '_' . $parts['filename']; 122 } else { 123 $partial = $parts['dirname'] . DIRECTORY_SEPARATOR . '_' . $parts['filename']; 124 } 125 126 if (isset($parts['extension'])) { 127 $partial .= '.' . $parts['extension']; 128 } 129 130 return $partial; 131 } 132} 133