SassFile.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. <?php
  2. /* SVN FILE: $Id: SassFile.php 118 2010-09-21 09:45:11Z chris.l.yates@gmail.com $ */
  3. /**
  4. * SassFile class file.
  5. * File handling utilites.
  6. * @author Chris Yates <chris.l.yates@gmail.com>
  7. * @copyright Copyright (c) 2010 PBM Web Development
  8. * @license http://phamlp.googlecode.com/files/license.txt
  9. * @package PHamlP
  10. * @subpackage Sass
  11. */
  12. /**
  13. * SassFile class.
  14. * @package PHamlP
  15. * @subpackage Sass
  16. */
  17. class SassFile {
  18. const SASS = 'sass';
  19. const SCSS = 'scss';
  20. const SASSC = 'sassc';
  21. private static $extensions = array(self::SASS, self::SCSS);
  22. /**
  23. * Returns the parse tree for a file.
  24. * If caching is enabled a cached version will be used if possible; if not the
  25. * parsed file will be cached.
  26. * @param string filename to parse
  27. * @param SassParser Sass parser
  28. * @return SassRootNode
  29. */
  30. public static function getTree($filename, $parser) {
  31. if ($parser->cache) {
  32. $cached = self::getCachedFile($filename, $parser->cache_location);
  33. if ($cached !== false) {
  34. return $cached;
  35. }
  36. }
  37. $sassParser = new SassParser(array_merge($parser->options, array('line'=>1)));
  38. $tree = $sassParser->parse($filename);
  39. if ($parser->cache) {
  40. self::setCachedFile($tree, $filename, $parser->cache_location);
  41. }
  42. return $tree;
  43. }
  44. /**
  45. * Returns the full path to a file to parse.
  46. * The file is looked for recursively under the load_paths directories and
  47. * the template_location directory.
  48. * If the filename does not end in .sass or .scss try the current syntax first
  49. * then, if a file is not found, try the other syntax.
  50. * @param string filename to find
  51. * @param SassParser Sass parser
  52. * @return string path to file
  53. * @throws SassException if file not found
  54. */
  55. public static function getFile($filename, $parser) {
  56. $ext = substr($filename, -5);
  57. foreach (self::$extensions as $i=>$extension) {
  58. if ($ext !== '.'.self::SASS && $ext !== '.'.self::SCSS) {
  59. if ($i===0) {
  60. $_filename = "$filename.{$parser->syntax}";
  61. }
  62. else {
  63. $_filename = $filename.'.'.($parser->syntax === self::SASS ? self::SCSS : self::SASS);
  64. }
  65. }
  66. else {
  67. $_filename = $filename;
  68. }
  69. if (file_exists($_filename)) {
  70. return $_filename;
  71. }
  72. foreach (array_merge(array(dirname($parser->filename)), $parser->load_paths) as $loadPath) {
  73. $path = self::findFile($_filename, realpath($loadPath));
  74. if ($path !== false) {
  75. return $path;
  76. }
  77. } // foreach
  78. if (!empty($parser->template_location)) {
  79. $path = self::findFile($_filename, realpath($parser->template_location));
  80. if ($path !== false) {
  81. return $path;
  82. }
  83. }
  84. }
  85. throw new SassException('Unable to find {what}: {filename}', array('{what}'=>'import file', '{filename}'=>$filename));
  86. }
  87. /**
  88. * Looks for the file recursively in the specified directory.
  89. * This will also look for _filename to handle Sass partials.
  90. * @param string filename to look for
  91. * @param string path to directory to look in and under
  92. * @return mixed string: full path to file if found, false if not
  93. */
  94. public static function findFile($filename, $dir) {
  95. $partialname = dirname($filename).DIRECTORY_SEPARATOR.'_'.basename($filename);
  96. foreach (array($filename, $partialname) as $file) {
  97. if (file_exists($dir . DIRECTORY_SEPARATOR . $file)) {
  98. return realpath($dir . DIRECTORY_SEPARATOR . $file);
  99. }
  100. }
  101. $files = array_slice(scandir($dir), 2);
  102. foreach ($files as $file) {
  103. if (is_dir($dir . DIRECTORY_SEPARATOR . $file)) {
  104. $path = self::findFile($filename, $dir . DIRECTORY_SEPARATOR . $file);
  105. if ($path !== false) {
  106. return $path;
  107. }
  108. }
  109. } // foreach
  110. return false;
  111. }
  112. /**
  113. * Returns a cached version of the file if available.
  114. * @param string filename to fetch
  115. * @param string path to cache location
  116. * @return mixed the cached file if available or false if it is not
  117. */
  118. public static function getCachedFile($filename, $cacheLocation) {
  119. $cached = realpath($cacheLocation) . DIRECTORY_SEPARATOR .
  120. md5($filename) . '.'.self::SASSC;
  121. if ($cached && file_exists($cached) &&
  122. filemtime($cached) >= filemtime($filename)) {
  123. return unserialize(file_get_contents($cached));
  124. }
  125. return false;
  126. }
  127. /**
  128. * Saves a cached version of the file.
  129. * @param SassRootNode Sass tree to save
  130. * @param string filename to save
  131. * @param string path to cache location
  132. * @return mixed the cached file if available or false if it is not
  133. */
  134. public static function setCachedFile($sassc, $filename, $cacheLocation) {
  135. $cacheDir = realpath($cacheLocation);
  136. if (!$cacheDir) {
  137. mkdir($cacheLocation);
  138. @chmod($cacheLocation, 0777);
  139. $cacheDir = realpath($cacheLocation);
  140. }
  141. $cached = $cacheDir . DIRECTORY_SEPARATOR . md5($filename) . '.'.self::SASSC;
  142. return file_put_contents($cached, serialize($sassc));
  143. }
  144. }